sduacm16级寒假训练 自测
2017-02-16 16:15
351 查看
POJ 3579 Median
【sol】显然,每个点与其他的点形成的差是有序的,这样相当于有n组升序的序列,询问中位数。二分中位数,然
后判断比他小的数的个数,复杂度n* logn*logn
#include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include<algorithm> using namespace std; typedef long long LL; const int N = 100000 + 50; int a , n, m; bool cal(int x) { int num = 0; for(int i = 0; i < n; i++) num += n - (lower_bound(a, a + n, a[i] + x) - a); return(num > m / 2); } int main() { while(~scanf("%d", &n)) { m = n * (n - 1) / 2; for(int i = 0; i < n; i++) scanf("%d", &a[i]); sort(a, a + n); int l = 0, r = 1e9 + 5; int ans; while(l <= r) { int mid = (l + r) >> 1; if (cal(mid)) { ans = mid; // cout<<"fu"<<ans<<endl; l = mid + 1; } else r = mid - 1; } printf("%d\n", ans); } return 0; }
POJ 1742 Coins
【sol】裸的多重背包,但是普通的多重背包会超时,但是如果一件物品的总体积如果超过背包总体积的话,完全可
以用完全背包搞,这样可以优化时间复杂度。
#include<cstdio> #include<iostream> #include<cstring> const int N = 100000 + 50; bool f ; int a , c , v , top, ans; using namespace std; int n, m; void cal(int x, int num) { int tot = 1; while(num >= tot) { v[++top] = tot * x; num -= tot; tot *= 2; } if (num) v[++top] = num * x; } int main() { while(~scanf("%d%d", &n, &m) && n) { memset(f, 0, sizeof(f)); top = 0; ans = 0; for(int i = 0; i < n; i++) scanf("%d", &a[i]); for(int i = 0; i< n; i++) scanf("%d", &c[i]); for(int i = 0; i < n; i++) if(a[i] * c[i] < m) cal(a[i], c[i]); f[0] = true; for(int i = 1; i <= top; i++) for(int j = m; j >= v[i]; j--) f[j] = f[j] || f[j - v[i]]; for(int i = 0; i < n; i++) if(a[i] * c[i] >= m) for(int j = a[i]; j <= m; j++) f[j] = f[j] || f[j - a[i]]; for(int j = 1; j <= m; j++) if (f[j]) ans++; printf("%d\n", ans); } return 0; }
Visible Lattice Points
没找到来源………..【Pro】
给定整数n, 询问有多少对(i,j),(i,j < n),使得gcd(i,j) = 1,有多组数据
【sol】
完全可以先暴力出来所有答案(没错,就是打表,,,,),如果这道题的数据范围变大的话,其实可以用
欧拉函数来搞,即ans = ∑f(i),先用nlogn来搞出f(i)的值…
#include<cstdio> #include<iostream> #include<cstring> const int N = 1000 + 50; int f , Case = 0; using namespace std; int n, m, T; int gcd(int a, int b) { if(b == 0) return a; return gcd(b, a % b); } int main() { f[1] = 3; for(int t = 2; t <= 1000; t++) { f[t] = f[t - 1]; for(int i = 1; i < t; i++) if (gcd(i, t) == 1) f[t] += 2; } scanf("%d", &T); while(T--) { scanf("%d", &n); printf("%d %d %d\n", ++Case, n, f ); } return 0; }
POJ 1845 Sumdiv(数论,求A^B的所有约数和)
【sol】先质因数分解一下,假设为2^a1 * 3^ a2* 5^a3然后因子和就是(2^0 + 2^ 1 + 2^ 2+…..+2^ a1)*(3^0 +
3^1 + …..+3^ a2) *(5^0 + …. + 5^a3),这样每项用等比数列公式来搞就可以了,但是公式有除法,就需要
逆元了
【吐槽】
wa掉了好多发,注意两个问题,第一,即公比为1的时候特殊处理,第二,当p为9901时,此时结果并不为
零…毕竟0^0 = 1
#include<cstdio> #include<iostream> #include<cstring> #include<cmath> using namespace std; typedef long long LL; const int N = 10000 + 50; const int P = 9901; LL p , a , top = 0, n, m, inv ; void cal(LL n) { for(int i = 2; i <= sqrt(n); i++) if (n % i == 0) { top++; p[top] = i; while (n % i == 0) { a[top]++; n /= i; } } if (n > 1) { p[++top] = n; a[top] = 1; } } LL quick(LL a, LL b) { LL ans = 1; a = a % P; while(b) { if (b % 2 == 1) ans = ans * a % P; b /= 2; a = a * a % P; } return ans; } int main() { inv[1] = 1; for(int i = 2; i < P; i++) { inv[i] = (P - P / i) * inv[P % i]; inv[i] %= P; } while(cin>>n>>m){ if (n == 0) { printf("0"); continue; } top = 0; memset(a, 0, sizeof(a)); cal(n); LL ans = 1; for(int i = 1; i <= top; i++) { p[i] %= P; if (p[i] == 0) { // printf("0"); // ans = 1; continue; } if(p[i] == 1) { LL tot = a[i] * m + 1; tot %= P; ans = ans * tot % P; continue; } // cout<<"test"<<p[i]<<"ko"<<a[i] * m + 1<<endl; LL tot = quick(p[i], a[i] * m + 1); // cout<<"tot"<<tot<<endl; tot = (tot - 1 + P); tot = (tot % P )* inv[p[i] - 1]; // cout<<"tot"<<tot<<endl; ans = ans * tot % P; } cout<<ans; } return 0; }
POJ1837 Balance
【sol】此问题等价于一组物品中只能选取一件物品,询问某价值的方案数,即把一系列的挂钩的权重与砝码的乘积
组成一组物品,这里的权重会有负数,最后的答案就是f[0]
#include<cstdio> #include<iostream> using namespace std; const int N = 5000 * 2; int f[20 + 5] ; int w[20 + 5], a[20 + 5]; int main() { int n, m; scanf("%d%d", &n, &m); for(int i = 0; i < n; i++) scanf("%d", &a[i]); for(int i = 0; i < m; i++) scanf("%d", &w[i]); f[0][5000] = 1; for(int i = 0; i < m; i++) { for(int j = 0; j <= 10000; j++) if (f[i][j] != 0) for(int k = 0; k < n; k++) { int t = j + a[k] * w[i]; f[i + 1][t] += f[i][j]; // printf("f[%d,%d]=%d\n", i + 1, t, f[i + 1][t]); } } printf("%d", f[m][5000]); return 0; }
POJ 3267 The Cow Lexicon
【sol】暴力,显然不现实,用dp来搞,f[i]代表前i个字符的最大匹配长度,这样f[i] = f[j] + new,这样考虑每一步
的决策,即判断一个字符串是否是另外一个字符串的子串,可以用O(n)来搞,但是对于每个区间,都需要与
每个单词匹配一下,这样如果m个单词,长度为n的字符串,复杂度为n* n* m*m,我们需要优化,如果字
符串的(l,r)可以匹配某单词的话,(l,r + 1),(l,r + 2)都可以了,所以预处理的时候枚举起点,做一次匹配,这
样对于不同的终点不需要再次匹配了
#include<cstdio> #include<iostream> using namespace std; string a[600 + 5]; string ss; const int N = 300 + 5; int n, m; int tot , f ; int cal(int t, string s2) { int l = 0; int k = ss.length(); for(int i = t; i < ss.length(); i++) { if (ss[i] == s2[l]) l++; if (l == s2.length()) { k = i; break; } } return k; } int main() { scanf("%d%d", &m, &n); cin>>ss; for(int i = 0; i < m; i++) cin>>a[i]; for(int i = 0; i < n; i++) { for(int j = 0; j < m; j++) { int t = cal(i, a[j]); // if (t != ss.length()) // printf("%d ~ %d\n", i, t); int ans = a[j].length(); for(int k = t; k < ss.length(); k++) tot[i][k] = max(tot[i][k], ans); } } for(int i = 1; i <= n; i++) for(int j = 0; j < i; j++) f[i] = max(f[i], f[j] + tot[j][i - 1]); printf("%d", n - f ); return 0; }
相关文章推荐
- sduacm16级寒假训练 贪心二分
- sduacm16级寒假训练 素筛 快速幂 GCD
- sduacm16级寒假训练 贪心二分
- sduacm16级寒假训练 素筛 快速幂 GCD
- sduacm16级寒假训练 动态规划(二)
- sduacm16级寒假训练 搜索与背包
- sduacm16级寒假训练 动态规划(一)
- sduacm16级寒假训练 搜索与背包
- sduacm16级寒假热身赛解题报告
- sduacm16级寒假热身
- SDUACM16级寒假热身1
- sduacm16级寒假训练 动态规划(一)
- Acm寒假训练有感
- SEU寒假训练题解二 D Codeforces 439A
- 寒假填空训练一1010删字母(滚动数组或replace(进行string的删除)),学习一下string的replace以及string的相加
- 2017寒假集训-小题训练1:C - Patrick and Shopping
- 寒假训练——POJ - 2488 A Knight's Journey 搜索+贪心
- 2016寒假训练——字典树
- 2016寒假训练——栈模拟
- 寒假训练01G:hdu1260