2016-2017 ACM-ICPC CHINA-Final Solution
Problem A. Number Theory Problem
Solved.
水。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 1e5 + 10; 6 7 typedef long long ll; 8 9 int n; 10 ll arr[maxn], ans[maxn]; 11 12 void Init() 13 { 14 arr[0] = 1; 15 for(int i = 1; i <= maxn; ++i) 16 { 17 arr[i] = (arr[i - 1] * 2) % 7; 18 ans[i] = ans[i - 1]; 19 if(arr[i] == 1) ans[i]++; 20 } 21 } 22 23 int main() 24 { 25 Init(); 26 int t; 27 scanf("%d",&t); 28 for(int cas = 1; cas <= t; ++cas) 29 { 30 scanf("%d", &n); 31 printf("Case #%d: %lld\n", cas, ans[n]); 32 } 33 return 0; 34 }
Problem B. Hemi Palindrome
Unsolved.
题意:
定义$Hemi Palindrome$ 为去掉所有奇数位上的数字后是回文串或者去掉所有偶数位上的数是回文串,给出一个长度$N$
构造一个字典序最小的$Hemi Palindrome$
Problem C. Mr. Panda and Strips
Upsolved.
题意:
选择序列中两段不相交的连续区间,要求这两段区间并没有重复数字,求最长长度。
思路:
双指针枚举第一个区间,然后再左段和右段再双指针枚举最长的合并区间
我们考虑双指针扩展右指针的过程中,也可以更新答案
但是对于已经在前一个左指针上扩展过的,就没有必要扩展了。
.....L......R........
我们考虑枚举的时候是这样的
那么L.......R 这一段没有必要再检查是否有更大的答案,因为如果有,那么必然是L - 1........R 是更大的
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 1010 5 #define M 100010 6 int t, n, a[N]; 7 int vis[M][2]; 8 9 int solve(int ql, int qr) 10 { 11 int res = 0; 12 for (int i = ql, r = ql - 1; i <= qr; ++i) 13 { 14 if (r < i) r = i - 1; 15 while (r < qr && !vis[a[r + 1]][0] && !vis[a[r + 1]][1]) 16 { 17 ++r; 18 vis[a[r]][1] = 1; 19 } 20 res = max(res, r - i + 1); 21 vis[a[i]][1] = 0; 22 } 23 return res; 24 } 25 26 int main() 27 { 28 scanf("%d", &t); 29 for (int kase = 1; kase <= t; ++kase) 30 { 31 printf("Case #%d: ", kase); 32 scanf("%d", &n); 33 for (int i = 1; i <= n; ++i) scanf("%d", a + i); 34 memset(vis, 0, sizeof vis); 35 int res = 0; 36 for (int i = 1, r = 0; i <= n; ++i) 37 { 38 while (r < n && !vis[a[r + 1]][0]) 39 { 40 ++r; 41 vis[a[r]][0] = 1; 42 res = max(res, r - i + 1 + max(solve(1, i - 1), solve(r + 1, n))); 43 } 44 int tmp = max(solve(1, i - 1), solve(r + 1, n)); 45 res = max(res, r - i + 1 + tmp); 46 vis[a[i]][0] = 0; 47 } 48 printf("%d\n", res); 49 } 50 return 0; 51 }
Problem D. Ice Cream Tower
Solved.
题意:
要构造一个冰激凌塔,并且要求$第i层的尺寸需要 >= 第 i - 1 层的尺寸 \cdot 2$
给出n个冰激凌的尺寸,求最多构造多少个K层的塔
思路:
二分答案,贪心摆放。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 const int maxn = 3e5 + 10; 7 8 int n, k; 9 ll arr[maxn]; 10 ll tower[maxn]; 11 12 bool check(int mid) 13 { 14 int now = 1; 15 for(int i = 1; i <= mid; ++i) tower[i] = arr[now++]; 16 for(int i = mid + 1; i <= mid * k; ++i) 17 { 18 while(now <= n && arr[now] < tower[i - mid] * 2) ++now; 19 if(now > n) return false; 20 tower[i] = arr[now++]; 21 } 22 return true; 23 } 24 25 int main() 26 { 27 int t; 28 scanf("%d", &t); 29 for(int cas = 1; cas <= t; ++cas) 30 { 31 scanf("%d %d", &n, &k); 32 for(int i = 1; i <= n; ++i) scanf("%lld", arr + i); 33 sort(arr + 1, arr + 1 + n); 34 int l = 0, r = n / k, res = 0; 35 while(r - l >= 0) 36 { 37 int mid = (l + r) >> 1; 38 if(check(mid)) 39 { 40 l = mid + 1; 41 res = mid; 42 } 43 else r = mid - 1; 44 } 45 printf("Case #%d: %d\n", cas, res); 46 } 47 return 0; 48 }
Problem E. Bet
Solved.
题意:
有一家赌球公司,你要赌球,对于每一支队伍 赔率是$A_i : B_i$
你要如何下注,使得如果有一只球队赢了,你就不会亏本,求你最多能下注的数量。
思路:
假设本金为1, 考虑对$第i支球队下注p_i 那么需要满足 p_i + p_i \cdot \frac{B_i}{A_i} > 1 $
移项之后即为$p_i > \frac{A_i}{A_i + B_i}$
那么对所有球队按这个式子从小到大排序,取到大于一就不取了
注意精度问题,数据保证小数点后最多三位,直接$ * 1000$
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 const double eps = 1e-8; 8 const ll MOD = 1e9 + 7; 9 const ll INFLL = 0x3f3f3f3f3f3f3f3f; 10 const int INF = 0x3f3f3f3f; 11 const int maxn = 1e5 + 10; 12 13 int n; 14 long double arr[maxn]; 15 16 void RUN() 17 { 18 int t; 19 scanf("%d", &t); 20 for (int cas = 1; cas <= t; ++cas) 21 { 22 scanf("%d", &n); 23 for (int i = 1; i <= n; ++i) 24 { 25 long double ai, bi; 26 scanf("%Lf:%Lf", &ai, &bi); 27 ai = (int)(ai * 1000 + 0.1); 28 bi = (int)(bi * 1000 + 0.2); 29 arr[i] = ai / (ai + bi); 30 } 31 sort(arr + 1, arr + 1 + n); 32 long double sum = 0; 33 int cnt = 0; 34 for (int i = 1; i <= n; ++i) 35 { 36 sum += arr[i]; 37 if (sum >= (long double)1.0) break; 38 cnt++; 39 } 40 printf("Case #%d: %d\n", cas, cnt); 41 } 42 } 43 44 int main() 45 { 46 #ifdef LOCAL_JUDGE 47 freopen("Text.txt", "r", stdin); 48 #endif // LOCAL_JUDGE 49 50 RUN(); 51 52 #ifdef LOCAL_JUDGE 53 fclose(stdin); 54 #endif // LOCAL_JUDGE 55 56 return 0; 57 }
Problem F. Mr. Panda and Fantastic Beasts
Unsolved.
Problem G. Pandaria
Unsolved.
Problem H. Great Cells
Solved.
题意:
定义$Ag 矩阵中恰好有g个好点的方案数,定义好点为那一个点所在的行和列它最大,严格最大$
求$\sum_{i = 0}^{i = n * m} (g + 1) * A_g$
思路:
考虑将式子拆成
$\sum_{g = 0}^{g = n * m} g * A_g + \sum_{g = 0}^{g = n * m}A_g$
显然 右边的项的答案就是$k^{n * m}$
再考虑左边
如果我把式子 除以$\sum_{g = 1}^{g = n * m} A_g$
那么整个式子表达的含义即$g$ 的数学期望
我们再考虑用另一种方法求数学期望
$E \cdot \sum_{g = 1}^{g = n * m} A_g = n * m * \sum_{i = 2}^{i = k} (i - 1) ^ {n + m - 2} \cdot k ^{(n - 1) * (m - 1)}$
含义是 令$i为好点的值,有多少种方案,那么显然,任意一个点都可以是好点,那么同行同列的取值为[1, i - 1]$
$其它格子的取值随意$
那么等式右边算出来的即是$所有g的总和$
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 const ll MOD = 1e9 + 7; 8 9 ll qpow(ll x, ll n) 10 { 11 ll res = 1; 12 while(n) 13 { 14 if(n & 1) res = res * x % MOD; 15 x = x * x % MOD; 16 n >>= 1; 17 } 18 return res; 19 } 20 21 int t; 22 int n, m, k; 23 24 int main() 25 { 26 scanf("%d", &t); 27 for(int cas = 1; cas <= t; ++cas) 28 { 29 scanf("%d %d %d", &n, &m, &k); 30 ll ans = 0; 31 for(int i = 2; i <= k; ++i) 32 { 33 ans = (ans + n * m % MOD * qpow(i - 1, n + m - 2) % MOD * qpow(k, (n - 1) * (m - 1)) % MOD) % MOD; 34 } 35 ans = (ans + qpow(k, n * m)) % MOD; 36 printf("Case #%d: %lld\n", cas, ans); 37 } 38 return 0; 39 }
Problem I. Cherry Pick
Unsolved.
Problem J. Mr.Panda and TubeMaster
Unsolved.
Problem K. Justice Rains From Above
Unsolved.
Problem L. World Cup
Solved.
水。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 int arr[3] = {3, 1, 0}; 6 int brr[3] = {0, 1, 3}; 7 int ans[10][10][10][10]; 8 9 void Init() 10 { 11 for(int i1 = 0; i1 < 3; ++i1) 12 { 13 for(int i2 = 0; i2 < 3; ++i2) 14 { 15 for(int i3 = 0; i3 < 3; ++i3) 16 { 17 for(int i4 = 0; i4 < 3; ++i4) 18 { 19 for(int i5 = 0; i5 < 3; ++i5) 20 { 21 for(int i6 = 0; i6 < 3; ++i6) 22 { 23 int a = arr[i1] + arr[i2] + arr[i3]; 24 int b = brr[i1] + arr[i4] + arr[i5]; 25 int c = brr[i2] + brr[i4] + arr[i6]; 26 int d = brr[i3] + brr[i5] + brr[i6]; 27 ans[a][b][c][d]++; 28 } 29 } 30 } 31 } 32 } 33 } 34 } 35 36 int a, b, c, d; 37 38 int main() 39 { 40 Init(); 41 int t; 42 scanf("%d", &t); 43 for(int cas = 1; cas <= t; ++cas) 44 { 45 scanf("%d %d %d %d",&a, &b, &c, &d); 46 printf("Case #%d: ", cas); 47 if(a > 9 || b > 9 || c > 9 || d > 9) puts("Wrong Scoreboard"); 48 else if(ans[a][b][c][d] > 1) puts("No"); 49 else if(ans[a][b][c][d]) puts("Yes"); 50 else puts("Wrong Scoreboard"); 51 } 52 return 0; 53 }