[USACO Training] Section 2.3
2016-08-22 10:27
330 查看
PROB Longest Prefix
给定一些(length 1..200)小字符串(length 1..10)和一个大字符串(length 1..200,000),求大字符串的前缀中能由小字符串拼接得到的最大长度。递推,朴素地比较就可以。看到字符串这么长,朴素地比较有点虚……想到NOI 2016 Day1 T1和前辈用strcmp水阿狸的打字机的故事,我决定试一试。正如ANALYSIS所言,字符串比较的最坏情况不易达到,常数也小;可以用Trie优化。
写以下代码的时候我忘记了
strncmp这个东西。
/* ID: chrt2001 PROG: prefix LANG: C++ */ #include <cstdio> #include <cstring> using namespace std; char p[201][11], s[200001]; int l[200]; bool f[200000]; int main() { freopen("prefix.in", "r", stdin); freopen("prefix.out", "w", stdout); int m = 0, n = 0, ans = 0; while ((~scanf("%s", p[m])) && p[m][0] != '.') { l[m] = strlen(p[m]); ++m; } while (~scanf("%s", s+n)) while (s ) ++n; char c; for (int i = 0; i < n; ++i) { c = s[i+1]; s[i+1] = 0; for (int j = 0; j < m; ++j) if (i+1 >= l[j] && (i-l[j] == -1 || f[i-l[j]]) && strcmp(s+i-l[j]+1, p[j]) == 0) { f[i] = true; ans = i+1; break; } s[i+1] = c; } printf("%d\n", ans); return 0; }
PROB Cow Pedigrees
求一共有N个(3 <= N < 200)结点、高度为K(1 < K < 100)、每个结点有0或2个儿子的树的个数,对9901取模。联想到两个东西:一是卡特兰数,二是用高度小于等于K的减去高度小于等于(K-1)的得到高度等于K的。
本题的名字和某wiki很像。
/* ID: chrt2001 PROG: nocows LANG: C++ */ #include <cstdio> using namespace std; const int M = 9901; int f[100][200]; int main() { freopen("nocows.in", "r", stdin); freopen("nocows.out", "w", stdout); int n, k; scanf("%d %d", &n, &k); if (n % 2 == 0 || k > n/2+1) { puts("0"); return 0; } f[1][1] = 1; for (int i = 2; i <= k; ++i) { f[i][1] = 1; for (int j = 3; j <= n; j += 2) for (int t = 1; t < j-1; t += 2) f[i][j] = (f[i][j] + f[i-1][t]*f[i-1][j-1-t]) % M; } printf("%d\n", (f[k] - f[k-1] + M) % M); return 0; }
PROB Zero Sum
求在1~n <= 9之间填+、
-或不填,结果为0的表达式,按字典序输出。
枚举一下就好。我是一边枚举一边计算的,也可以像ANALYSIS那样最后再算。
/* ID: chrt2001 PROG: zerosum LANG: C++ */ #include <cstdio> using namespace std; enum op {BEGIN, BLANK=' ', PLUS='+', MINUS='-'}; char s[10]; int n; inline void print() { putchar('1'); for (int i = 2; i <= n; ++i) printf("%c%d", s[i], i); putchar('\n'); } // k ~ 当前数字;x ~ 上一个数;r ~ 先前的结果;pre ~ 上一个非空操作;now ~ 当前操作 void search(int k, int x, int r, op pre, op now) { s[k] = char(now); switch (now) { case BLANK: if (pre == PLUS) r += 9*x + k; else r -= 9*x + k; x = 10*x + k; break; case PLUS: r += k; x = k; break; case MINUS: r -= k; x = k; } if (k == n) { if (r == 0) print(); return; } op o = now == BLANK ? pre : now; search(k+1, x, r, o, BLANK); search(k+1, x, r, o, PLUS); search(k+1, x, r, o, MINUS); } int main() { freopen("zerosum.in", "r", stdin); freopen("zerosum.out", "w", stdout); scanf("%d", &n); search(1, 0, 0, BEGIN, PLUS); return 0; }
PROB Money Systems
那个作为错误贪心范例的经典DP问题。注意这里隐含着滚动数组,所以不能把两维循环的顺序搞反。(开始我搞反了QAQ)
/* ID: chrt2001 PROG: money LANG: C++ */ #include <cstdio> using namespace std; typedef long long ll; const int MAX_N = 10000, MAX_V = 25; ll f[MAX_N+1]; int c[MAX_V]; int main() { freopen("money.in", "r", stdin); freopen("money.out", "w", stdout); int v, n; scanf("%d %d", &v, &n); for (int i = 0; i < v; ++i) scanf("%d", &c[i]); f[0] = 1; for (int i = 0; i < v; ++i) for (int j = 1; j <= n; ++j) f[j] += (j >= c[i] ? f[j-c[i]] : 0); printf("%lld\n", f ); return 0; }
PROB Controlling Companies
公司A拥有公司B当且仅当满足下述条件中至少一个:- A=B。
- A拥有B大于50%的股权。
- A拥有的公司中拥有B的股权之和大于50%。
给定一些股权所有信息,求所有的拥有关系,不用输出自己拥有自己。公司不超过100个。
从每个点开始BFS。用队列维护它拥有的点,向外更新。
ANALYSIS用了诡异的递归。
/* ID: chrt2001 PROG: concom LANG: C++ */ #include <cstdio> #include <queue> #include <algorithm> #include <cstring> using namespace std; const int MAX_N = 100, MAX_P = 50; bool control[MAX_N+1][MAX_N+1]; int n, M[MAX_N+1][MAX_N+1], p[MAX_N+1]; queue<int> Q; void search(int x) { memset(p+1, 0, sizeof(int)*n); Q.push(x); control[x][x] = true; int u; while (!Q.empty()) { u = Q.front(); Q.pop(); for (int v = 1; v <= n; ++v) if (M[u][v]) { p[v] += M[u][v]; if (p[v] > MAX_P && !control[x][v]) { Q.push(v); control[x][v] = true; } } } } int main() { freopen("concom.in", "r", stdin); freopen("concom.out", "w", stdout); int m; scanf("%d", &m); for (int i = 0; i < m; ++i) { int x, y, p; scanf("%d %d %d", &x, &y, &p); n = max(n, max(x, y)); M[x][y] += p; } for (int i = 1; i <= n; ++i) search(i); for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) if (control[i][j] && i != j) printf("%d %d\n", i, j); return 0; }
相关文章推荐
- USACO Section2.3 Money Systems 解题报告 【icedream61】
- [USACO Training] Section 2.2
- USACO-Section2.3 Longest Prefix【动态规划】
- USACO-Section 2.3 Cow Pedigrees(DP)
- [USACO Training] Section 1.4
- USACO Training Section 1.2 Greedy Gift Givers
- USACO-Section2.3 Money Systems
- USACO - Chapter2 Section 2.3 - Longest Prefix
- [USACO Training] Section 1.1
- [USACO Training] Section 1.5
- USACO(含training section)水题合集[5/未完待续]
- C++——USACO Section 2.3 题解
- USACO-Section2.3 Cow Pedigrees【动态规划】
- USACO Training Section 1.1 [USACO1.1]你的飞碟在这儿Your Ride Is Here
- 【USACO Training】Section 2.1 Ordered Fractions
- USACO-Section 2.3 Zero Sum(枚举)
- [USACO Training] Section 1.3
- USACO Section 2.3 Fractions to Decimals
- [USACO Training] Section 2.4
- USACO-Section2.3 Controlling Companies【深度优先搜索】