2016 CCPC 长春 Solution
A - Hanzo vs. Genji
留坑。
B - Fraction
水。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 inline int gcd(int a, int b) 5 { 6 return b ? gcd(b, a % b) : a; 7 } 8 9 int t, n; 10 int a[10], b[10]; 11 12 int main() 13 { 14 scanf("%d", &t); 15 for (int kase = 1; kase <= t; ++kase) 16 { 17 scanf("%d", &n); 18 for (int i = 1; i <= n; ++i) scanf("%d", a + i); 19 for (int i = 1; i <= n; ++i) scanf("%d", b + i); 20 int p = b[n], q = a[n]; 21 for (int i = n - 1; i >= 1; --i) 22 { 23 int tq = a[i] * q + p; 24 int tp = b[i] * q; 25 p = tp, q = tq; 26 int Gcd = gcd(p, q); p /= Gcd, q /= Gcd; 27 } 28 int Gcd = gcd(p, q); p /= Gcd, q /= Gcd; 29 printf("Case #%d: %d %d\n", kase, p, q); 30 } 31 return 0; 32 }
C - Rotate String
留坑。
D - Triangle
水。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int fic[25]; 5 6 int t, n; 7 8 int main() 9 { 10 fic[0] = fic[1] = 1; 11 for (int i = 2; i <= 20; ++i) fic[i] = fic[i - 1] + fic[i - 2]; 12 scanf("%d", &t); 13 for (int kase = 1; kase <= t; ++kase) 14 { 15 scanf("%d", &n); 16 int pos = upper_bound(fic + 1, fic + 21, n) - fic; 17 printf("Case #%d: %d\n", kase, n - pos + 1); 18 } 19 return 0; 20 }
E - The Fastest Runner Ms. Zhang
留坑。
F - Harmonic Value Description
题意:有一个1-n的全排列,定义一个值$\sum_{i = 1}^{i = n - 1} gcd(p_i, p_{i + 1})$ 求这个值第k大的数列
思路:首先相邻的奇数的gcd为1,相邻的偶数的gcd为2
分类讨论:k=1输出原序列
k为偶数,将k和2*k提前输出在按照原序列输出,提供的贡献就是k-1
k为奇数,将3开始的k-1个奇数提前,其他按照原序列输出,每个奇数的提前会导致左右的偶数产生贡献为2
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 10010 6 7 int n, k; 8 int arr[N]; 9 int vis[N]; 10 11 int main() 12 { 13 int t; 14 scanf("%d",&t); 15 for(int cas = 1; cas <= t; ++cas) 16 { 17 scanf("%d %d",&n, &k); 18 printf("Case #%d:", cas); 19 memset(vis, 0, sizeof vis); 20 if(k == 1) 21 { 22 for(int i = 1; i <= n; ++i) arr[i] = i; 23 } 24 else if(k % 2 == 0) 25 { 26 arr[1] = k; 27 arr[2] = 2 * k; 28 int cnt = 3; 29 for(int i = 1; i <= n; ++i) 30 { 31 if(i == k || i == 2 * k) continue; 32 arr[cnt++] = i; 33 } 34 } 35 else 36 { 37 int cnt = 1; 38 int num = 3; 39 for(int i = 1; i < k; ++i) 40 { 41 arr[cnt++] = num; 42 vis[num] = 1; 43 num += 2; 44 } 45 for(int i = 1; i <= n; ++i) 46 { 47 if(vis[i]) continue; 48 arr[cnt++] = i; 49 } 50 } 51 for(int i = 1; i <= n; ++i) printf(" %d", arr[i]); 52 printf("\n"); 53 } 54 return 0; 55 }
G - Instability
题意:有n个点,m条边,求有多少个点的子集,使得这个子集中点的个数$>= 3$ 并且这个子集中存在三个点互相可达,或者互相不可达
思路:根据拉姆齐定理,当点数$>= 6$ 的时候,必然存在这种情况,对于点数3, 4, 5 直接暴力求解
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 6 const ll MOD = (ll)1e9 + 7; 7 8 ll fac[60], inv[60]; 9 10 inline ll qpow(ll base, ll n) 11 { 12 ll res = 1; 13 while (n) 14 { 15 if (n & 1) res = res * base % MOD; 16 base = base * base % MOD; 17 n >>= 1; 18 } 19 return res; 20 } 21 22 inline void Fac_Init() 23 { 24 fac[0] = 1; 25 for (int i = 1; i < 60; ++i) 26 fac[i] = fac[i - 1] * i % MOD; 27 inv[59] = qpow(fac[59], MOD - 2); 28 for (int i = 58; i >= 0; --i) 29 inv[i] = inv[i + 1] * (i + 1) % MOD; 30 } 31 32 inline ll C(int a, int b) 33 { 34 if (b > a) return 0; 35 if (b == 0) return 1; 36 return fac[a] * inv[b] % MOD * inv[a - b] % MOD; 37 } 38 39 //ll C[55][55]; 40 // 41 //void I() { 42 // for (int i = 0; i < 55; i++) C[i][0] = 1; 43 // for (int i = 1; i < 55; i++) { 44 // for (int j = 1; j <= i; j++) { 45 // C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD; 46 // } 47 // } 48 //} 49 50 int t, n, m; 51 bool G[60][60]; 52 int a[5]; 53 54 inline bool ok(int sz) 55 { 56 for (int i = 0; i < sz; ++i) 57 for (int j = i + 1; j < sz; ++j) 58 for (int k = j + 1; k < sz; ++k) 59 { 60 if (G[a[i]][a[j]] && G[a[j]][a[k]] && G[a[i]][a[k]]) return true; 61 if (!G[a[i]][a[j]] && !G[a[j]][a[k]] && !G[a[i]][a[k]]) return true; 62 } 63 return false; 64 } 65 66 inline ll work() 67 { 68 ll res = 0; 69 for (a[0] = 1; a[0] <= n; ++a[0]) 70 for (a[1] = a[0] + 1; a[1] <= n; ++a[1]) 71 for (a[2] = a[1] + 1; a[2] <= n; ++a[2]) 72 { 73 if (ok(3)) res = (res + 1) >= MOD ? (res + 1 - MOD) : (res + 1); 74 for (a[3] = a[2] + 1; a[3] <= n; ++a[3]) 75 { 76 if (ok(4)) res = (res + 1) >= MOD ? (res + 1 - MOD) : (res + 1); 77 for (a[4] = a[3] + 1; a[4] <= n; ++a[4]) 78 if (ok(5)) res = (res + 1) >= MOD ? (res + 1 - MOD) : (res + 1); 79 } 80 } 81 return res; 82 } 83 84 inline void Run() 85 { 86 Fac_Init(); 87 scanf("%d", &t); 88 for (int kase = 1; kase <= t; ++kase) 89 { 90 printf("Case #%d: ", kase); 91 scanf("%d%d", &n, &m); 92 memset(G, 0, sizeof G); 93 for (int i = 1, u, v; i <= m; ++i) 94 { 95 scanf("%d%d", &u, &v); 96 G[u][v] = G[v][u] = 1; 97 } 98 ll ans = 0; 99 if (n >= 6) 100 { 101 for (int i = 6; i <= n; ++i) 102 ans = (ans + C(n, i)) % MOD; 103 } 104 ans = (ans + work()) % MOD; 105 printf("%lld\n", ans); 106 } 107 } 108 109 int main() 110 { 111 #ifdef LOCAL 112 freopen("Test.in", "r", stdin); 113 #endif 114 115 Run(); 116 return 0; 117 }
H - Sequence I
题意:给出$arr[]$和$brr[]$ 给出p 求有多少个q 满足 $a_q, a_{q + p}, a_{q + 2p}.....a_{q + (m - 1)p}$ 和$brr[]$ 能够匹配上
思路:多次KMP 注意求nx数组的时候,要用模板中的第一个,不知道为啥。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 1000010 6 7 int arr[N]; 8 int brr[N]; 9 10 int n, m, p; 11 12 inline void preKMP(int x[], int m, int kmpNext[]) 13 { 14 int i, j; 15 j = kmpNext[0] = -1; 16 i = 0; 17 while(i < m) 18 { 19 while(-1 != j && x[i] != x[j]) j = kmpNext[j]; 20 kmpNext[++i] = ++j; 21 } 22 } 23 24 int nxt[N]; 25 26 int KMP_count(int x[], int m, int y[], int n) 27 { 28 preKMP(x, m, nxt); 29 int ans = 0; 30 for(int k = 0; k < p; ++k) 31 { 32 int i = k, j = 0; 33 while(i < n) 34 { 35 while(j != -1 && y[i] != x[j]) j = nxt[j]; 36 i += p;j++; 37 if(j >= m) 38 { 39 ans++; 40 j = nxt[j]; 41 } 42 } 43 } 44 return ans; 45 } 46 47 int main() 48 { 49 int t; 50 scanf("%d", &t); 51 for(int cas = 1; cas <= t; ++cas) 52 { 53 scanf("%d %d %d",&n, &m, &p); 54 for(int i = 0; i < n; ++i) scanf("%d", arr + i); 55 for(int i = 0; i < m; ++i) scanf("%d", brr + i); 56 int ans = KMP_count(brr, m, arr, n); 57 printf("Case #%d: %d\n", cas, ans); 58 } 59 return 0; 60 }
I - Sequence II
题意:给出一个$arr[]$ ,每次询问给出l, r 求这个区间内第一次出现的数中,第K个数的下标
思路:裸的主席树
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 200010 5 #define M N * 50 6 7 int t, n, q, ans; 8 int vis[N], arr[N]; 9 int T[N], L[M], R[M], C[M], tot; 10 11 inline int build(int l, int r) 12 { 13 int root = tot++; 14 C[root] = 0; 15 if (l < r) 16 { 17 int mid = (l + r) >> 1; 18 L[root] = build(l, mid); 19 R[root] = build(mid + 1, r); 20 } 21 return root; 22 } 23 24 inline int update(int root, int pos, int val) 25 { 26 int newroot = tot++, tmp = newroot; 27 C[newroot] = C[root] + val; 28 int l = 1, r = n; 29 while (l < r) 30 { 31 int mid = (l + r) >> 1; 32 if (pos <= mid) 33 { 34 L[newroot] = tot++, R[newroot] = R[root]; 35 newroot = L[newroot], root = L[root]; 36 r = mid; 37 } 38 else 39 { 40 L[newroot] = L[root], R[newroot] = tot++; 41 newroot = R[newroot], root = R[root]; 42 l = mid + 1; 43 } 44 C[newroot] = C[root] + val; 45 } 46 return tmp; 47 } 48 49 inline int query(int root, int pos) 50 { 51 int l = 1, r = n; 52 int res = 0; 53 while (l < r) 54 { 55 int mid = (l + r) >> 1; 56 if (pos <= mid) 57 { 58 root = L[root]; 59 r = mid; 60 } 61 else 62 { 63 res += C[L[root]]; 64 root = R[root]; 65 l = mid + 1; 66 } 67 } 68 return res + C[root]; 69 } 70 71 inline int query2(int root, int k) 72 { 73 int l = 1, r = n; 74 int res = 0; 75 while (l < r) 76 { 77 int mid = (l + r) >> 1; 78 if (C[L[root]] >= k) 79 { 80 root = L[root]; 81 r = mid; 82 } 83 else 84 { 85 k -= C[L[root]]; 86 root = R[root]; 87 l = mid + 1; 88 } 89 } 90 return l; 91 92 } 93 94 int main() 95 { 96 scanf("%d", &t); 97 for (int kase = 1; kase <= t; ++kase) 98 { 99 printf("Case #%d:", kase); 100 scanf("%d%d", &n, &q); tot = 0; 101 for (int i = 1; i <= n; ++i) scanf("%d", arr + i); 102 T[n + 1] = build(1, n); 103 memset(vis, 0, sizeof vis); 104 for (int i = n; i >= 1; --i) 105 { 106 if (vis[arr[i]] == 0) 107 { 108 T[i] = update(T[i + 1], i, 1); 109 } 110 else 111 { 112 T[i] = update(T[i + 1], vis[arr[i]], -1); 113 T[i] = update(T[i], i, 1); 114 } 115 vis[arr[i]] = i; 116 } 117 ans = 0; 118 for (int i = 1, l, r; i <= q; ++i) 119 { 120 scanf("%d%d", &l, &r); 121 l = (l + ans) % n + 1; 122 r = (r + ans) % n + 1; 123 if (l > r) swap(l, r); 124 if (l == r) 125 { 126 printf(" %d", l); 127 ans = l; 128 continue; 129 } 130 int k = query(T[l], r); k = (k + 1) / 2; 131 ans = query2(T[l], k); 132 printf(" %d", ans); 133 } 134 puts(""); 135 } 136 return 0; 137 }
J - Ugly Problem
题意:给出一个数,求这个数能够被多少个回文数相加得到,个数不能超过50,输出这些数
思路:如果是10000 这样的数,那么就取9999 否则 就是 位数减半的前一位-1然后右半部分回文得到回文数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 int main() { 6 int t; 7 char st[10000]; 8 int a[10000],b[10000],ans[100][10000]; 9 int x,y; 10 int i,j,k,len,cnt,kase; 11 scanf("%d",&t); 12 kase=0; 13 while (t--) { 14 printf("Case #%d:\n",++kase); 15 scanf("%s",st); 16 len=strlen(st); 17 for (i=0;i<len;++i) 18 a[len-i]=st[i]-48; 19 x=len; 20 cnt=0; 21 while (x>1) { 22 cnt++; 23 k=x/2+1; 24 memset(b,0,sizeof b); 25 while (k<=x) { 26 if (a[k]==0) b[k]=9; 27 else 28 { 29 b[k]=a[k]-1; 30 k++; 31 break; 32 } 33 k++; 34 } 35 while (k<=x) { 36 b[k]=a[k]; 37 k++; 38 } 39 y=x; 40 for (i=1;i<=x/2;++i) 41 b[i]=b[y-i+1]; 42 if (b[y]==0) {b[1]=9; y--;} 43 ans[cnt][0]=y; 44 for (i=y;i>=1;--i) { 45 ans[cnt][i]=b[i]; 46 //printf("%d",b[i]); 47 a[i]=a[i]-b[i]; 48 } 49 //printf("\n"); 50 for (i=1;i<=x;++i) 51 if (a[i]<0) { 52 a[i]=a[i]+10; 53 a[i+1]--; 54 } 55 while (a[x]==0) --x; 56 } 57 if (a[1]!=0) {cnt++; ans[cnt][0]=1; ans[cnt][1]=a[1];} 58 printf("%d\n",cnt); 59 for (i=1;i<=cnt;++i) { 60 for (j=ans[i][0];j>=1;--j) printf("%d",ans[i][j]); 61 printf("\n"); 62 } 63 } 64 return 0; 65 }
K - Binary Indexed Tree
留坑。