2016年中国大学生程序设计竞赛(杭州)-重现赛
2016-10-29 17:35
465 查看
虽说天冷打代码冻手,但是退役的时候打一把比赛还是蛮爽的。
感觉今天状态很差,06没考虑负数,最后一题脑残写反判定? 真的要退役了。
A
贪心模拟,不够就一直合并,多的话就一直分解。
B
考虑每个SCC的入度,然后统计贡献。注意特判1的情况的。
C
贪心,从后向前模拟。
但是直接用double精度可能会不够,最好的方法就是使用分数的形式。
D
首先打个表,发现y<1010。
高效的枚举y,可以将y分两半,类似科学计数法记y=x∗105+y,里面x和y均小于105。预处理前一半,然后统计个数,再枚举后一半,统计贡献。
注意y>0。。。。
代码写的太弱智
F
注意考虑负数的情况,初始化0的活该WA
K
存在两个大于n的素数显然是不合法的,而且对于重叠的区间,最优方案是自己和自己匹配,这样就把点数优化到600的规模。跑匹配即可。n和s还可以写反?
感觉今天状态很差,06没考虑负数,最后一题脑残写反判定? 真的要退役了。
A
贪心模拟,不够就一直合并,多的话就一直分解。
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <map> #include <cmath> #include <iostream> using namespace std; typedef long long LL; const int MAXN = 1e5 + 10; const int MOD = 1e9 + 7; typedef pair<int, int> pii; LL a[MAXN]; int main() { int t, kcase = 1; scanf("%d", &t); while(t--) { int n, m; scanf("%d%d", &n, &m); LL sum = 0; for(int i = 1; i <= n; i++) { scanf("%lld", &a[i]); sum += a[i]; } if(sum % m) { printf("Case #%d: -1\n", kcase++); continue; } LL ans = 0; LL aver = sum / m; int i = 1; for(int j = 1; j <= m && i <= n; i++) { while(i <= n && a[i] < aver) { a[i + 1] += a[i]; i++; ans++; } while(a[i] > aver) { a[i] -= aver; ans++; j++; } if(a[i] == aver) { j++; } else { a[i + 1] += a[i]; ans++; } } printf("Case #%d: %lld\n", kcase++, ans); } return 0; }
B
考虑每个SCC的入度,然后统计贡献。注意特判1的情况的。
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <map> #include <cmath> #include <vector> #include <stack> #include <iostream> using namespace std; typedef long long LL; const int MAXN = 1e3 + 10; const int MOD = 1e9 + 7; const int INF = 1e9 + 7; typedef pair<int, int> pii; vector<int> G[MAXN]; vector<int> scc[MAXN]; int x[MAXN], y[MAXN], r[MAXN], c[MAXN]; int low[MAXN], dfn[MAXN]; int dfs_clock; bool Instack[MAXN]; int scc_cnt; int sccno[MAXN]; stack<int> S; void tarjan(int u, int fa) { int v; low[u] = dfn[u] = ++dfs_clock; Instack[u] = true; S.push(u); for(int i = 0; i < G[u].size(); i++) { v = G[u][i]; if(!dfn[v]) { tarjan(v, u); low[u] = min(low[u], low[v]); } else if(Instack[v]) { low[u] = min(low[u], dfn[v]); } } if(low[u] == dfn[u]) { scc_cnt++; scc[scc_cnt].clear(); for(;;) { v = S.top(); S.pop(); sccno[v] = scc_cnt; scc[scc_cnt].push_back(v); Instack[v] = false; if(v == u) break; } } } void find_cut(int l, int r) { memset(low, 0, sizeof(low)); memset(dfn, 0, sizeof(dfn)); memset(sccno, 0, sizeof(sccno)); memset(Instack, false, sizeof(Instack)); dfs_clock = scc_cnt = 0; for(int i = l; i <= r; i++) { if(!dfn[i]) { tarjan(i, -1); } } } int in[MAXN]; int main() { int t, kcase = 1; scanf("%d", &t); while(t--) { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d%d%d%d", &x[i], &y[i], &r[i], &c[i]); } for(int i = 1; i <= n; i++) { G[i].clear(); for(int j = 1; j <= n; j++) { if(i == j) continue; if(1LL * (x[j] - x[i]) * (x[j] - x[i]) + 1LL * (y[j] - y[i]) * (y[j] - y[i]) <= 1LL * r[i] * r[i]) { G[i].push_back(j); } } } find_cut(1, n); for(int i = 1; i <= scc_cnt; i++) in[i] = 0; for(int i = 1; i <= n; i++) { for(int j = 0; j < G[i].size(); j++) { int u = sccno[i]; int v = sccno[G[i][j]]; if(u != v) { in[v]++; } } } LL ans = 0; if(scc_cnt == 1) { sort(c + 1, c + n + 1); ans = c[1]; } else { for(int i = 1; i <= scc_cnt; i++) { if(in[i]) continue; int Min = INF; for(int j = 0; j < scc[i].size(); j++) { Min = min(Min, c[scc[i][j]]); } ans += Min; } } printf("Case #%d: %lld\n", kcase++, ans); } return 0; }
C
贪心,从后向前模拟。
但是直接用double精度可能会不够,最好的方法就是使用分数的形式。
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <map> #include <vector> #include <stack> #include <cmath> #include <iostream> using namespace std; typedef unsigned long long LL; const int MAXN = 1e5 + 10; const int MOD = 1e9 + 7; const int INF = 1e9 + 7; typedef pair<int, int> pii; LL a[MAXN]; LL gcd(LL a, LL b) { return b == 0 ? a : gcd(b, a % b); } int main() { int t, kcase = 1; scanf("%d", &t); while(t--) { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%llu", &a[i]); } LL ans = 1; a[0] = 0; LL v1 = a - a[n - 1]; LL v2 = 1; for(int i = n - 1; i >= 1; i--) { LL d = a[i] - a[i - 1]; if(v1 >= d * v2) { v1 = d; v2 = 1; ans++; } else { if((d * v2) % v1 == 0) { ans += d * v2 / v1; } else { LL num = d * v2 / v1 + 1; v1 = d; v2 = num; LL GCD = gcd(v1, v2); v1 /= GCD; v2 /= GCD; ans += num; } } } printf("Case #%d: %llu\n", kcase++, ans); } return 0; }
D
首先打个表,发现y<1010。
高效的枚举y,可以将y分两半,类似科学计数法记y=x∗105+y,里面x和y均小于105。预处理前一半,然后统计个数,再枚举后一半,统计贡献。
注意y>0。。。。
代码写的太弱智
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <map> #include <cmath> #include <iostream> using namespace std; typedef long long LL; const int MAXN = 1e4 + 10; const int MOD = 1e9 + 7; typedef pair<int, int> pii; LL f[10][10]; LL W(int bit) { LL ans = 0; for(int i = 1; i <= bit; i++) { ans = ans * 10 + 9; } return ans; } LL sum[100000 + 10][10]; LL rec[100000 + 10], val[100000 + 10]; int num[100000 + 10]; int main() { for(int i = 0; i <= 9; i++) { for(int j = 1; j <= 9; j++) { f[i][j] = 1; for(int k = 1; k <= j; k++) { f[i][j] *= i; } } } // for(int i = 6; ; i++) { // if(1LL * 1000000000 + W(i) > 1LL * f[9][9] * i) { // printf("%d\n", i); break; // } // } // max(bit) = 10 for(int i = 0; i <= 100000; i++) { for(int k = 1; k <= 9; k++) { int n = i; sum[i][k] = 0; while(n) { sum[i][k] += f[n % 10][k]; n /= 10; } } } int t, kcase = 1; scanf("%d", &t); while(t--) { int x, k; scanf("%d%d", &x, &k); LL ans = 0; int top = 0; for(int i = 0; i < 100000; i++) { val[i] = sum[i][k] - 1LL * i * 100000 - x; rec[top++] = val[i]; num[i] = 0; } sort(rec, rec + top); int N = top; top = 1; for(int i = 1; i < N; i++) { if(rec[i] != rec[i - 1]) { rec[top++] = rec[i]; } } for(int i = 0; i < 100000; i++) { num[lower_bound(rec, rec + top, val[i]) - rec]++; } for(int i = 0; i < 100000; i++) { LL V = 1LL * i - sum[i][k]; int p = lower_bound(rec, rec + top, V) - rec; if(rec[p] == V) { ans += num[p]; } } if(x == 0) { ans--; } printf("Case #%d: %lld\n", kcase++, ans); } return 0; }
F
注意考虑负数的情况,初始化0的活该WA
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <map> #include <cmath> #include <iostream> using namespace std; typedef long long LL; const int MAXN = 1e5 + 10; const int MOD = 1e9 + 7; const int INF = 1e9 + 7; typedef pair<int, int> pii; char str[100]; int main() { int t, kcase = 1; scanf("%d", &t); while(t--) { scanf("%s", str); int len = strlen(str); LL ans = -INF; for(int i = 0; i < len - 4; i++) { for(int j = i + 1; j < len - 3; j++) { LL a = 0; for(int k = 0; k <= i; k++) { a = a * 10 + (str[k] - '0'); } LL b = 0; for(int k = i + 1; k <= j; k++) { b = b * 10 + (str[k] - '0'); } LL c = str[j + 1] - '0'; LL d = str[j + 2] - '0'; LL e = 0; for(int k = j + 3; k < len; k++) { e = e * 10 + (str[k] - '0'); } ans = max(ans, a + b - c * d / e); } } printf("Case #%d: %lld\n", kcase++, ans); } return 0; }
K
存在两个大于n的素数显然是不合法的,而且对于重叠的区间,最优方案是自己和自己匹配,这样就把点数优化到600的规模。跑匹配即可。n和s还可以写反?
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <map> #include <vector> #include <stack> #include <cmath> #include <iostream> using namespace std; typedef long long LL; const int MAXN = 1e5 + 10; const int MOD = 1e9 + 7; const int INF = 1e9 + 7; typedef pair<int, int> pii; vector<int> G[1000]; int match[1000]; bool used[1000]; bool DFS(int u) { for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if(!used[v]) { used[v] = true; if(match[v] == -1 || DFS(match[v])) { match[v] = u; return true; } } } return false; } void Solve(int n) { memset(match, -1, sizeof(match)); int ans = 0; for(int i = 1; i <= n; i++) { memset(used, false, sizeof(used)); ans += DFS(i); } printf(ans == n ? "Yes\n" : "No\n"); } int main() { int t, kcase = 1; scanf("%d", &t); while(t--) { int n, s; scanf("%d%d", &n, &s); printf("Case #%d: ", kcase++); if(s >= n) { if(n >= 600) { printf("No\n"); } else { for(int i = 1; i <= n; i++) { G[i].clear(); for(int j = 1; j <= n; j++) { if((s + j) % i == 0) { G[i].push_back(j); } } } Solve(n); } } else { if(s >= 600) { printf("No\n"); } else { for(int i = 1; i <= s; i++) { G[i].clear(); for(int j = 1; j <= s; j++) { if((j + n) % i == 0) { G[i].push_back(j); } } } Solve(s); } } } return 0; }
相关文章推荐
- (2016年中国大学生程序设计竞赛(杭州)-重现赛) ArcSoft's Office Rearrangement 模拟
- 2016年中国大学生程序设计竞赛(杭州)-重现赛
- (2016年中国大学生程序设计竞赛(杭州)-重现赛) Car 二分 (解决精度问题)
- 2016年中国大学生程序设计竞赛(杭州)-重现赛【01,02,03,06】
- HDU 5934 Bomb 【图论缩点】(2016年中国大学生程序设计竞赛(杭州))
- 2016年中国大学生程序设计竞赛(合肥)-重现赛(感谢安徽大学)(5/10)
- HDU 5934 Bomb 【图论缩点】(2016年中国大学生程序设计竞赛(杭州))
- 2016年中国大学生程序设计竞赛(合肥)-重现赛1009 HDU 5969
- hdu 5936 二分好题 2016年中国大学生程序设计竞赛(杭州)
- HDU 5936 Difference(思维+二分)——2016年中国大学生程序设计竞赛(杭州)
- HDU 5935 Car 【模拟】 (2016年中国大学生程序设计竞赛(杭州))
- 2016年中国大学生程序设计竞赛(合肥)-重现赛1008 HDU 5968
- HDU 5935 Car 【模拟】 (2016年中国大学生程序设计竞赛(杭州))
- HDU 5937 Equation 【DFS+剪枝】 (2016年中国大学生程序设计竞赛(杭州))
- 2016年中国大学生程序设计竞赛(合肥)-重现赛1001 HDU 5961
- HDU 5938 Four Operations 【贪心】(2016年中国大学生程序设计竞赛(杭州))
- HDU 5937 Equation 【DFS+剪枝】 (2016年中国大学生程序设计竞赛(杭州))
- 2016年中国大学生程序设计竞赛(合肥)-重现赛
- HDU 5938 Four Operations 【贪心】(2016年中国大学生程序设计竞赛(杭州))
- HDU 5935 Car (贪心)——2016年中国大学生程序设计竞赛(杭州)