Codeforces Round #369 (Div. 2) ABCDE题解
2016-08-30 21:02
806 查看
A. Bus to Udayland
水题,枚举字符并判断,无坑点
B. Chris and Magic Square
水题,先记录0出现的位置,然后用已知的行和,求出应该填写的数,再判断是否相等。注意要特判n=1的情况。
C. Coloring Trees
简单dp,dp[i][j][k]表示第i个位置,颜色为j,段数为k的最小花费。我比较蠢- -,分了4种情况(当前位置和上一个位置是否为0)讨论(比赛时有个细节写错了结果fst。状态转移方程见代码。时间复杂度是O(n*m^2*k),用cf的测评机跑不会超时。
D. Directed Roads
简单图论+计数。(qwb说的对,确实是水题
题目意思是给你一个可能有环的有向图,你可以翻转一些边(原来u->v变成v->u),使得原图变为一个DAG,输出方案数。
思路比较直接,跑一遍tarjan统计出每个强连通分量的节点数,对于节点数num>2的强连通分量来说,我们必须翻转其中的[1,num-1](也就是(2^num)-2)条边。然后对于其余强连通分量(也就是不属于num>2的scc的节点),我们可选可不选,也就是有2^tmp种情况。然后把以上两种情况的所有结果相乘即可。
E. ZS and The Birthday Paradox
简单数学题。
一年2^n天,求k个人中有人生日是同一天的概率(1<=n,k<=1e18)。
假如一年365天,n个人中有人生日相同的概率为
所以这一题就是让求
然后求出分子分母的gcd约分就可以了。gcd一定是2^x的形式,因为分母已经是2^x的形式,所以只需要求出分子的因子2的个数。
对于1*2*3*...*k,因子2的个数为k/2+k/4+k/8...。
然后求出gcd的逆元,分子分母同时乘上逆元就得到结果了。
水题,枚举字符并判断,无坑点
#include <map> #include <set> #include <cmath> #include <ctime> #include <queue> #include <stack> #include <string> #include <vector> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; typedef __int64 LL; typedef pair<int,int> PII; #define FIN freopen("in.txt", "r", stdin); #define FOUT freopen("out.txt", "w", stdout); #define lson l, mid, cur << 1 #define rson mid + 1, r, cur << 1 | 1 //#pragma comment(linker, "/STACK:1024000000,1024000000") const int INF = 0x3f3f3f3f; const LL INFLL = 0x3f3f3f3f3f3f3f3fLL; const double ERR = 1e-8; const int MOD = 1e9 + 7; const int MAXN = 1e3 + 50; const int MAXM = 5e3 + 50; int n, m; char s[MAXN][10]; int main() { #ifdef LOCAL_NORTH FIN; #endif // LOCAL_NORTH while (~scanf("%d", &n)) { bool ok = false; for (int i = 0; i < n; i++) { scanf("%s", s[i]); if (!ok) { if (s[i][0] == 'O' && s[i][1] == 'O') { s[i][0] = s[i][1] = '+'; ok = true; } if (!ok) { if (s[i][3] == 'O' && s[i][4] == 'O') { s[i][3] = s[i][4] = '+'; ok = true; } } } } if (!ok) puts("NO"); else { puts("YES"); for (int i = 0; i < n; i++) printf("%s\n", s[i]); } } #ifdef LOCAL_NORTH cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl; #endif // LOCAL_NORTH return 0; }
B. Chris and Magic Square
水题,先记录0出现的位置,然后用已知的行和,求出应该填写的数,再判断是否相等。注意要特判n=1的情况。
#include <map> #include <set> #include <cmath> #include <ctime> #include <queue> #include <stack> #include <string> #include <vector> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; typedef __int64 LL; typedef pair<int,int> PII; #define FIN freopen("in.txt", "r", stdin); #define FOUT freopen("out.txt", "w", stdout); #define lson l, mid, cur << 1 #define rson mid + 1, r, cur << 1 | 1 //#pragma comment(linker, "/STACK:1024000000,1024000000") const int INF = 0x3f3f3f3f; const LL INFLL = 0x3f3f3f3f3f3f3f3fLL; const double ERR = 1e-8; const int MOD = 1e9 + 7; const int MAXN = 500 + 50; const int MAXM = 5e3 + 50; int n, num[MAXN][MAXN]; LL c[MAXN], r[MAXN], d1, d2; int main() { #ifdef LOCAL_NORTH FIN; #endif // LOCAL_NORTH while (~scanf("%d", &n)) { memset(c, 0, sizeof(c)); memset(r, 0, sizeof(r)); d1 = d2 = 0; int x, y; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { scanf("%d", &num[i][j]); if (num[i][j] == 0) { x = i; y = j; continue; } r[i] += num[i][j]; c[j] += num[i][j]; if (i == j) d1 += num[i][j]; if (i + j == n - 1) d2 += num[i][j]; } } if (n == 1) { puts("1"); continue; } LL ans = 0; if (x > 0) ans = r[x - 1] - r[x]; else ans = r[x + 1] - r[x]; r[x] += ans; c[y] += ans; if (x == y) d1 += ans; if (x + y == n - 1) d2 += ans; bool ok = true; LL flag = r[0]; for (int i = 0; i < n; i++) { if (r[i] != flag || c[i] != flag) { ok = false; break; } } if (d1 != flag || d2 != flag) ok = false; if (!ok || ans <= 0) puts("-1"); else printf("%I64d\n", ans); } #ifdef LOCAL_NORTH cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl; #endif // LOCAL_NORTH return 0; }
C. Coloring Trees
简单dp,dp[i][j][k]表示第i个位置,颜色为j,段数为k的最小花费。我比较蠢- -,分了4种情况(当前位置和上一个位置是否为0)讨论(比赛时有个细节写错了结果fst。状态转移方程见代码。时间复杂度是O(n*m^2*k),用cf的测评机跑不会超时。
#include <map> #include <set> #include <cmath> #include <ctime> #include <queue> #include <stack> #include <string> #include <vector> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; typedef __int64 LL; typedef pair<int,int> PII; #define FIN freopen("in.txt", "r", stdin); #define FOUT freopen("out.txt", "w", stdout); #define lson l, mid, cur << 1 #define rson mid + 1, r, cur << 1 | 1 //#pragma comment(linker, "/STACK:1024000000,1024000000") const int INF = 0x3f3f3f3f; const LL INFLL = 0x3f3f3f3f3f3f3f3fLL; const double ERR = 1e-8; const int MOD = 1e9 + 7; const int MAXN = 100 + 50; const int MAXM = 5e3 + 50; int n, m, k, c[MAXN], cost[MAXN][MAXN]; LL dp[MAXN][MAXN][MAXN]; int main() { #ifdef LOCAL_NORTH FIN; #endif // LOCAL_NORTH while (~scanf("%d%d%d", &n, &m, &k)) { memset(dp, INFLL, sizeof(dp)); memset(cost, 0, sizeof(cost)); for (int i = 1; i <= n; i++) scanf("%d", &c[i]); if (!c[1]) c[0] = 101; else c[0] = c[1]; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { scanf("%d", &cost[i][j]); } } for (int i = 1; i <= m; i++) { dp[0][i][0] = 0; } for (int i = 1; i <= m; i++) { if (c[1]) dp[1][c[1]][1] = 0; else dp[1][i][1] = cost[1][i]; } for (int i = 1; i <= n; i++) { if (c[i]) { if (c[i - 1]) { for (int l = 1; l < i; l++) { if (c[i] == c[i - 1]) dp[i][c[i]][l] = min(dp[i][c[i]][l], dp[i - 1][c[i - 1]][l]); else dp[i][c[i]][l + 1] = min(dp[i][c[i]][l + 1], dp[i - 1][c[i - 1]][l]); } } else { for (int j = 1; j <= m; j++) { for (int l = 1; l < i; l++) { if (c[i] == j) dp[i][j][l] = min(dp[i][j][l], dp[i - 1][j][l]); else dp[i][c[i]][l + 1] = min(dp[i][c[i]][l + 1], dp[i - 1][j][l]); } } } } else { if (c[i - 1]) { for (int j = 1; j <= m; j++) { for (int l = 1; l < i; l++) { if (j == c[i - 1]) dp[i][j][l] = min(dp[i][j][l], dp[i - 1][j][l] + cost[i][j]); else dp[i][j][l + 1] = min(dp[i][j][l + 1], dp[i - 1][c[i - 1]][l] + cost[i][j]); } } } else { for (int j1 = 1; j1 <= m; j1++) { for (int j2 = 1; j2 <= m; j2++) { for (int l = 1; l < i; l++) { if (j1 == j2) dp[i][j1][l] = min(dp[i][j1][l], dp[i - 1][j1][l] + cost[i][j1]); else dp[i][j1][l + 1] = min(dp[i][j1][l + 1], dp[i - 1][j2][l] + cost[i][j1]); } } } } } } LL ans = INFLL; if (c ) ans = min(ans, dp [c ][k]); else for (int i = 1; i <= m; i++) { ans = min(ans, dp [i][k]); } printf("%I64d\n", ans == INFLL ? -1 : ans); } #ifdef LOCAL_NORTH cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl; #endif // LOCAL_NORTH return 0; }
D. Directed Roads
简单图论+计数。(qwb说的对,确实是水题
题目意思是给你一个可能有环的有向图,你可以翻转一些边(原来u->v变成v->u),使得原图变为一个DAG,输出方案数。
思路比较直接,跑一遍tarjan统计出每个强连通分量的节点数,对于节点数num>2的强连通分量来说,我们必须翻转其中的[1,num-1](也就是(2^num)-2)条边。然后对于其余强连通分量(也就是不属于num>2的scc的节点),我们可选可不选,也就是有2^tmp种情况。然后把以上两种情况的所有结果相乘即可。
#include <map> #include <set> #include <cmath> #include <ctime> #include <queue> #include <stack> #include <string> #include <vector> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; typedef __int64 LL; typedef pair<int,int> PII; #define FIN freopen("in.txt", "r", stdin); #define FOUT freopen("out.txt", "w", stdout); #define lson l, mid, cur << 1 #define rson mid + 1, r, cur << 1 | 1 //#pragma comment(linker, "/STACK:1024000000,1024000000") const int INF = 0x3f3f3f3f; const LL INFLL = 0x3f3f3f3f3f3f3f3fLL; const double ERR = 1e-8; const int MOD = 1e9 + 7; const int MAXN = 2e5 + 50; const int MAXM = 2e5 + 50; int n; struct edge { int to, nxt; } E[MAXM]; int Head[MAXN], tot; void edge_init() { tot = 0; memset(Head, -1, sizeof(Head)); } void edge_add(int u, int v) { E[tot].to = v; E[tot].nxt = Head[u]; Head[u] = tot++; } /* for (int i = 1; i <= n; i++) if (!DFN[i]) Tarjan(i); */ int Low[MAXN], DFN[MAXN], Stack[MAXN], Belong[MAXN], num[MAXN]; int Index, top, scc; bool InStack[MAXN]; void Tarjan_init() { memset(DFN, 0, sizeof(DFN)); memset(num, 0, sizeof(num)); memset(InStack, false, sizeof(InStack)); Index = scc = top = 0; } void Tarjan(int u) { int v; Low[u] = DFN[u] = ++Index; Stack[top++] = u; InStack[u] = true; for(int i = Head[u]; i != -1; i = E[i].nxt) { v = E[i].to; if( !DFN[v] ) { Tarjan(v); if( Low[u] > Low[v] )Low[u] = Low[v]; } else if(InStack[v] && Low[u] > DFN[v]) Low[u] = DFN[v]; } if(Low[u] == DFN[u]) { scc++; do { v = Stack[--top]; InStack[v] = false; Belong[v] = scc; num[scc]++; } while( v != u); } } LL fastpow(LL a, LL c) { LL res = 1; while (c) { if (c & 1) res = (res * a) % MOD; a = (a * a) % MOD; c >>= 1; } return res; } int main() { #ifdef LOCAL_NORTH FIN; #endif // LOCAL_NORTH while (~scanf("%d", &n)) { edge_init(); Tarjan_init(); for (int i = 1; i <= n; i++) { int t; scanf("%d", &t); edge_add(i, t); } for (int i = 1; i <= n; i++) if (!DFN[i]) Tarjan(i); LL ans = 1; int tmp = n; for (int i = 1; i <= scc; i++) { if (num[i] > 1) { ans = (ans * (fastpow(2, num[i]) - 2)) % MOD; tmp -= num[i]; } } if (tmp) ans = (ans * fastpow(2, tmp)) % MOD; printf("%I64d\n", ans); } #ifdef LOCAL_NORTH cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl; #endif // LOCAL_NORTH return 0; }
E. ZS and The Birthday Paradox
简单数学题。
一年2^n天,求k个人中有人生日是同一天的概率(1<=n,k<=1e18)。
假如一年365天,n个人中有人生日相同的概率为
所以这一题就是让求
然后求出分子分母的gcd约分就可以了。gcd一定是2^x的形式,因为分母已经是2^x的形式,所以只需要求出分子的因子2的个数。
对于1*2*3*...*k,因子2的个数为k/2+k/4+k/8...。
然后求出gcd的逆元,分子分母同时乘上逆元就得到结果了。
#include <map> #include <set> #include <cmath> #include <ctime> #include <queue> #include <stack> #include <string> #include <vector> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; typedef __int64 LL; typedef pair<int,int> PII; #define FIN freopen("in.txt", "r", stdin); #define FOUT freopen("out.txt", "w", stdout); #define lson l, mid, cur << 1 #define rson mid + 1, r, cur << 1 | 1 #define bitcnt(x) __builtin_popcount(x) #define bitcntll(x) __builtin_popcountll(x) //#pragma comment(linker, "/STACK:1024000000,1024000000") const int INF = 0x3f3f3f3f; const LL INFLL = 0x3f3f3f3f3f3f3f3fLL; const double ERR = 1e-8; const int MOD = 1e6 + 3; const int MAXN = 2e5 + 50; const int MAXM = 2e5 + 50; LL n, k; LL fastpow(LL a, LL c) { LL res = 1; while (c) { if (c & 1) res = (res * a) % MOD; a = (a * a) % MOD; c >>= 1; } return res; } int main() { #ifdef LOCAL_NORTH FIN; #endif // LOCAL_NORTH while (~scanf("%I64d%I64d", &n, &k)) { if (n <= 62 && k > (1LL << n)) { printf("1 1\n"); continue; } LL cnt = 0; LL p = fastpow(2, n); for (LL i = k - 1; i >= 1; i >>= 1) { cnt += i / 2; } // for (LL i = tmp - 1; i >= tmp - k + 1; i--) { // LL ttmp = i & (-i); // cnt += (LL)log2(ttmp); // } LL inv = fastpow(fastpow(2, cnt), MOD - 2); LL up = 1, down = fastpow(p, k - 1); for (LL i = 1; i <= k - 1; i++) { LL tmp = (p - i + MOD) % MOD; up = (up * tmp) % MOD; if (tmp <= 0) //!!! break; } up = up * inv % MOD; down = down * inv % MOD; up = (down - up + MOD) % MOD; printf("%I64d %I64d\n", up, down); } #ifdef LOCAL_NORTH cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl; #endif // LOCAL_NORTH return 0; }
相关文章推荐
- Codeforces Round #360 (Div. 2) ABCDE题解
- Codeforces Round #361 (Div. 2) ABCDE题解
- Codeforces Round #200 (Div. 2) (ABCDE题解)
- codeforces Intel Code Challenge Final Round (Div. 1 + Div. 2, Combined) 题解(A-D)
- Codeforces Round #306 (Div. 2) 题解
- Codeforces Round #306 (Div. 2) ABCDE(构造)
- Codeforces Round #292 DIV2 题解
- Codeforces Round #441 (Div. 2, by Moscow Team Olympiad) ABCD题解
- Codeforces Round #369 (Div. 2) [C] Coloring Trees
- codeforces round 315 div2 题解
- Codeforces Round #319 (Div. 2) (ABCE题解)
- Codeforces Round #369 (Div. 2) C. Coloring Trees 动态规划
- Codeforces Round #369 (Div. 2) A B 两水题 编码能力
- Codeforces Round #369 (Div. 2) C dp
- Codeforces Round #369 (Div. 2) D. Directed Roads (dfs+组合数学 图论)
- Codeforces Round #405 (rated, Div. 1, based on VK Cup 2017 Round 1) 题解(待续)
- Codeforces Round #361 (Div. 2) 题解
- Codeforces AIM Tech Round (Div. 2) 题解
- Codeforces Round #441 (Div. 2, by Moscow Team Olympiad) ABCD题解
- Codeforces Round #261 (Div. 2)[ABCDE]