CCPC-Wannafly Winter Camp Day2 (Div2, onsite)
Class
$A_i = a \cdot i \% n$
有 $A_i = k \cdot gcd(a, n)$
证明:
$A_0 = 0, A_x = x \cdot a - y \cdot n$
$令 d = gcd(a, n)$
$A_x \% d = (x \cdot a \% d - y \cdot n \% d) \% d = 0$ 得证
循环节为$\frac {n}{gcd(a, n)}$
Replay
Dup4:
- 自闭了,啥都不会,想开一道无人做的字符串,喵喵喵?
- 总是陷入思维的泥浆,爬不出来,T那么大,怎么就想不到预处理呢
X:
- 成功晋升码农
- 第三次忘记预处理是个啥,最后全靠队友一波rush
- 日常开局血崩,这口锅必须要背
Solution
A: Erase Numbers II
思路:
$n^2 暴力 注意最大的那项会爆 long\; long 但不会爆 unsigned \;long \;long$
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef unsigned long long ull; 6 const int maxn = 1e5 + 10; 7 8 int n; 9 ull arr[maxn]; 10 ull len[maxn]; 11 12 int main() 13 { 14 int t; 15 scanf("%d", &t); 16 for(int cas = 1; cas <= t; ++cas) 17 { 18 printf("Case #%d: ", cas); 19 scanf("%d", &n); 20 for(int i = 1; i <= n; ++i) 21 { 22 scanf("%llu", arr + i); 23 len[i] = 1; 24 ull x = arr[i]; 25 while(x) 26 { 27 len[i] *= 10; 28 x /= 10; 29 } 30 } 31 ull ans = 0; 32 for(int i = 1; i <= n; ++i) 33 { 34 for(int j = i + 1; j <= n; ++j) 35 { 36 ans = max(ans, arr[i] * len[j] + arr[j]); 37 } 38 } 39 printf("%llu\n", ans); 40 } 41 return 0; 42 }
B: Erase Numbers I
思路:
$将删除两个数当做两次操作$
$每次操作删除剩余串中长度最小$
$先O(n)扫一遍,如果找到一个长度最小并且字典序小于后一位的,即可直接上出,并且保证了最优$
$如果第一遍扫没找到合适的, 就从后往前找到第一个长度最小的删除$
$做两遍即可$
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int INF = 0x3f3f3f3f; 6 const int maxn = 1e4 + 10; 7 8 struct node{ 9 char str[20]; 10 int len; 11 int flag; 12 }arr[maxn]; 13 14 int n; 15 16 int main() 17 { 18 int t; 19 scanf("%d", &t); 20 for(int cas = 1; cas <= t; ++cas) 21 { 22 printf("Case #%d: ", cas); 23 scanf("%d", &n); 24 for(int i = 1; i <= n; ++i) 25 { 26 scanf("%s", arr[i].str); 27 arr[i].len = strlen(arr[i].str); 28 arr[i].flag = 0; 29 } 30 int pos1 = -1, pos2 = -1; 31 int Min = INF; 32 for(int i = 1; i <= n; ++i) if(!arr[i].flag) Min = min(Min, arr[i].len); 33 for(int i = 1; i <= n; ++i) 34 { 35 if(arr[i].flag) continue; 36 if(Min != arr[i].len) continue; 37 int j = i + 1; 38 while(arr[j].flag && j <= n) ++j; 39 if(j <= n) 40 { 41 if(strcmp(arr[i].str, arr[j].str) < 0) 42 { 43 pos1 = i; 44 arr[i].flag = 1; 45 break; 46 } 47 } 48 } 49 if(pos1 == -1) 50 { 51 for(int i = n; i >= 1; --i) 52 { 53 if(arr[i].flag) continue; 54 if(arr[i].len == Min) 55 { 56 arr[i].flag = 1; 57 pos1 = i; 58 break; 59 } 60 } 61 } 62 Min = INF; 63 for(int i = 1; i <= n; ++i) if(!arr[i].flag) Min = min(Min, arr[i].len); 64 for(int i = 1; i <= n; ++i) 65 { 66 if(arr[i].flag) continue; 67 if(Min != arr[i].len) continue; 68 int j = i + 1; 69 while(arr[j].flag && j <= n) ++j; 70 if(j <= n) 71 { 72 if(strcmp(arr[i].str, arr[j].str) < 0) 73 { 74 pos2 = i; 75 arr[i].flag = 1; 76 break; 77 } 78 } 79 } 80 if(pos2 == -1) 81 { 82 for(int i = n; i >= 1; --i) 83 { 84 if(arr[i].flag) continue; 85 if(arr[i].len == Min) 86 { 87 arr[i].flag = 1; 88 pos2 = i; 89 break; 90 } 91 } 92 } 93 for(int i = 1; i <= n; ++i) if(!arr[i].flag) printf("%s", arr[i].str); 94 puts(""); 95 } 96 return 0; 97 }
H: Cosmic Cleaner
思路:
$球缺体积$
$用一个平面截去一个球所得部分叫球缺$
$球缺面积 = 2 \cdot \pi h$
$球缺体积 = \pi \cdot h^2 \cdot (R - \frac{h}{3})$
$球缺质心:匀质球缺的质心位于它的中轴线上,并且与底面的距离为$
$C = \frac{(4\cdot R - h) \cdot h}{12 \cdot R - 4 \cdot h} = \frac{(d^2 + 2\cdot h^2) \cdot h}{3\cdot d^2 + 4\cdot h^2}$
$然后分分类 搞一搞,就好了$
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const double eps = 1e-8; 6 const double PI = acos(-1.0); 7 const int maxn = 1e2 + 10; 8 9 int sgn(double x) 10 { 11 if(fabs(x) < eps) return 0; 12 else return x > 0 ? 1 : -1; 13 } 14 15 struct node{ 16 double x, y, z, r; 17 node(){} 18 node(double x, double y, double z, double r): x(x), y(y), z(z), r(r){} 19 }O, P[maxn]; 20 21 double getdis(node p1, node p2) 22 { 23 double res = (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y) + (p1.z - p2.z) * (p1.z - p2.z); 24 res = sqrt(res); 25 return res; 26 } 27 28 int n; 29 30 int main() 31 { 32 int t; 33 scanf("%d", &t); 34 for(int cas = 1; cas <= t; ++cas) 35 { 36 printf("Case #%d: ", cas); 37 scanf("%d", &n); 38 for(int i = 1; i <= n; ++i) 39 { 40 scanf("%lf %lf %lf %lf", &P[i].x, &P[i].y, &P[i].z, &P[i].r); 41 } 42 scanf("%lf %lf %lf %lf", &O.x, &O.y, &O.z, &O.r); 43 double ans = 0; 44 for(int i = 1; i <= n; ++i) 45 { 46 double dis = getdis(O, P[i]); 47 double tmp = dis - O.r - P[i].r; 48 //out 49 if(sgn(tmp) > 0) 50 { 51 continue; 52 } 53 54 //in 55 if(sgn(dis + P[i].r - O.r) <= 0) 56 { 57 double tmp1 = 4.0 / 3.0 * PI * P[i].r * P[i].r * P[i].r; 58 ans += tmp1; 59 continue; 60 } 61 62 //part1 63 double r1 = O.r, r2 = P[i].r; 64 65 double r0 = (r1 * r1 + dis * dis - r2 * r2) / (2.0 * dis); 66 double h1 = r1 - r0; 67 68 ans += PI * h1 * h1 * (r1 - h1 / 3.0); 69 70 //part2 71 r0 = (r2 * r2 + dis * dis - r1 * r1) / (2.0 * dis); 72 double h2 = r2 - r0; 73 ans += PI * h2 * h2 * (r2 - h2 / 3.0); 74 } 75 printf("%.10f\n", ans); 76 } 77 return 0; 78 }
K: Sticks
思路:
将$l_i排序,接着n^3处理出合法的三角形关系,然后枚举三角形关系$
$注意不要重复枚举,但是暴力枚举常数还是太大$
$考虑一条剪枝,如果有一个三角关系,令其为a_1, a_2, a_3$
$如果存在 a_x >= a_3 和 a_1 以及 a_2 也同样满足大小关系,那么这个三角关系不用枚举$
$因为我们是从小到大枚举,在二三层循环当中枚举到的点的长度肯定比第一层的要大$
$那么对于a_x >= a_3 将a_x留在后面的三角关系中会使得答案更优$
然后就过了..
但实际上有一种更为科学的?方法
考虑合法的不重复的四对三角关系只有$\frac {C_{12}^3 \cdot C_{9}^3 \cdot C_6^3 }{4!}$
只有$15400 如果能够预处理出来,再暴力枚举的时间复杂度是对的$
考虑如何预处理
显然有个$O(220^4)的方法$
那么我们考虑能否优化掉第四维的$220$
$其实前三个三角关系确定了,第四个自然确定了,但是我们需要去重啊$
先考虑不重不漏的枚举三角关系 从小到大,并且每一个三角关系都有唯一编号
$用 Hash[][][] 进行Hash$
这样就可以$O(1)得到剩下的那个三角关系的编号,考虑编号和前三个三角关系编号的大小$
如果小了,那么肯定重复了
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 15 5 int t, l[N], vis[N]; 6 struct node 7 { 8 int x, y, z; 9 node () {} 10 node (int x, int y, int z) : x(x), y(y), z(z) {} 11 }; vector <node> v; 12 vector <int> res; 13 int Stack[100010], top; 14 15 bool ok(int x, int y, int z) 16 { 17 if (x + y > z && x + z > y && y + z > x) return 1; 18 return 0; 19 } 20 21 bool used(node a) 22 { 23 if (!vis[a.x] && !vis[a.y] && !vis[a.z]) return 0; 24 return 1; 25 } 26 27 void work(int i) 28 { 29 Stack[++top] = v[i].x; 30 Stack[++top] = v[i].y; 31 Stack[++top] = v[i].z; 32 vis[v[i].x] = 1; 33 vis[v[i].y] = 1; 34 vis[v[i].z] = 1; 35 } 36 37 void clear(int i) 38 { 39 top -= 3; 40 vis[v[i].x] = 0; 41 vis[v[i].y] = 0; 42 vis[v[i].z] = 0; 43 } 44 45 void add() 46 { 47 if (top > res.size()) 48 { 49 res.clear(); 50 for (int o = 1; o <= top; ++o) res.push_back(Stack[o]); 51 } 52 } 53 54 void solve() 55 { 56 int m = v.size(); 57 for (int i = 0; i < m; ++i) if (i == 0 || !(v[i].x == v[i - 1].x && v[i].y == v[i - 1].y)) 58 { 59 work(i); add(); 60 for (int j = i + 1; j < m; ++j) if (!used(v[j])) 61 { 62 work(j); add(); 63 for (int k = j + 1; k < m; ++k) if (!used(v[k])) 64 { 65 work(k); add(); 66 int a[3] = {0}, cnt = 0; 67 for (int o = 1; o <= 12; ++o) if (!vis[o]) 68 a[cnt++] = o; 69 if (ok(l[a[0]], l[a[1]], l[a[2]])) 70 { 71 for (int o = 0; o < 3; ++o) Stack[++top] = a[o]; 72 add(); 73 return; 74 } 75 clear(k); 76 } 77 clear(j); 78 } 79 clear(i); 80 } 81 } 82 83 int main() 84 { 85 scanf("%d", &t); 86 for (int kase = 1; kase <= t; ++kase) 87 { 88 printf("Case #%d: ", kase); top = 0; res.clear(); 89 memset(vis, 0, sizeof vis); 90 for (int i = 1; i <= 12; ++i) scanf("%d", l + i); 91 sort(l + 1, l + 13); 92 v.clear(); 93 for (int i = 1; i <= 12; ++i) for (int j = i + 1; j <= 12; ++j) for (int k = j + 1; k <= 12; ++k) if (ok(l[i], l[j], l[k])) 94 v.push_back(node(i, j, k)); 95 solve(); 96 int k = res.size() / 3; 97 printf("%d\n", k); 98 for (int i = 0, len = res.size(); i < len; ++i) printf("%d%c", l[res[i]], " \n"[(i + 1) % 3 == 0]); 99 } 100 return 0; 101 }
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 15 5 #define M 200100 6 int t, n, l[N], vis[N]; 7 8 struct node 9 { 10 int a[3]; 11 node () {} 12 node (int x, int y, int z) 13 { 14 a[0] = x; 15 a[1] = y; 16 a[2] = z; 17 } 18 bool ok() 19 { 20 if (l[a[0]] + l[a[1]] > l[a[2]] && l[a[0]] + l[a[2]] > l[a[1]] && l[a[1]] + l[a[2]] > l[a[0]]) return 1; 21 return 0; 22 } 23 void out() 24 { 25 for (int i = 0; i < 3; ++i) printf("%d%c", l[a[i]], " \n"[i == 2]); 26 } 27 }; vector <node> vec; 28 node que[M][5]; 29 node Stack[110]; int top; 30 int Hash[15][15][15]; 31 32 void used(node x) { for (int i = 0; i < 3; ++i) vis[x.a[i]] = 1; } 33 void clear(node x) { for (int i = 0; i < 3; ++i) vis[x.a[i]] = 0; --top; } 34 bool notused(node x) { for (int i = 0; i < 3; ++i) if (vis[x.a[i]]) return false; return true; } 35 36 void init() 37 { 38 int m = 0; 39 for (int i = 1; i <= 12; ++i) for (int j = i + 1; j <= 12; ++j) for (int k = j + 1; k <= 12; ++k) 40 { 41 vec.push_back(node(i, j, k)); 42 Hash[i][j][k] = m; 43 ++m; 44 } 45 n = 0; top = 0; 46 for (int i = 0; i < m; ++i) 47 { 48 Stack[++top] = vec[i]; 49 used(vec[i]); 50 for (int j = i + 1; j < m; ++j) if (notused(vec[j])) 51 { 52 Stack[++top] = vec[j]; 53 used(vec[j]); 54 for (int k = j + 1; k < m; ++k) if (notused(vec[k])) 55 { 56 Stack[++top] = vec[k]; 57 used(vec[k]); 58 node tmp; int cnt = 0; 59 for (int o = 1; o <= 12; ++o) if (!vis[o]) 60 tmp.a[cnt++] = o; 61 if (Hash[tmp.a[0]][tmp.a[1]][tmp.a[2]] > k) 62 { 63 Stack[++top] = tmp; 64 ++n; 65 for (int o = 1; o <= top; ++o) que[n][o] = Stack[o]; 66 --top; 67 } 68 clear(vec[k]); 69 } 70 clear(vec[j]); 71 } 72 clear(vec[i]); 73 } 74 } 75 76 int main() 77 { 78 init(); 79 scanf("%d", &t); 80 for (int kase = 1; kase <= t; ++kase) 81 { 82 printf("Case #%d: ", kase); 83 for (int i = 1; i <= 12; ++i) scanf("%d", l + i); 84 vector <node> res, tmp; 85 for (int i = 1; i <= n; ++i) 86 { 87 tmp.clear(); 88 for (int j = 1; j <= 4; ++j) if (que[i][j].ok()) 89 tmp.push_back(que[i][j]); 90 if (tmp.size() > res.size()) res = tmp; 91 if (res.size() == 4) break; 92 } 93 int k = res.size(); 94 printf("%d\n", k); 95 for (int i = 0; i < k; ++i) res[i].out(); 96 } 97 return 0; 98 }