2016 CCPC 长春 Solution
Posted dup4
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2016 CCPC 长春 Solution相关的知识,希望对你有一定的参考价值。
A - Hanzo vs. Genji
留坑。
B - Fraction
水。
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 ", kase, p, q); 30 } 31 return 0; 32 }
C - Rotate String
留坑。
D - Triangle
水。
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 ", 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
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(" "); 53 } 54 return 0; 55 }
G - Instability
留坑。
H - Sequence I
题意:给出$arr[]$和$brr[]$ 给出p 求有多少个q 满足 $a_q, a_{q + p}, a_{q + 2p}.....a_{q + (m - 1)p}$ 和$brr[]$ 能够匹配上
思路:多次KMP 注意求nx数组的时候,要用模板中的第一个,不知道为啥。
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 ", cas, ans); 58 } 59 return 0; 60 }
I - Sequence II
题意:给出一个$arr[]$ ,每次询问给出l, r 求这个区间内第一次出现的数中,第K个数的下标
思路:裸的主席树
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然后右半部分回文得到回文数
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: ",++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(" "); 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 ",cnt); 59 for (i=1;i<=cnt;++i) { 60 for (j=ans[i][0];j>=1;--j) printf("%d",ans[i][j]); 61 printf(" "); 62 } 63 } 64 return 0; 65 }
K - Binary Indexed Tree
留坑。
以上是关于2016 CCPC 长春 Solution的主要内容,如果未能解决你的问题,请参考以下文章
2016中国大学生程序设计竞赛(ccpc 长春) Fraction模拟
CCPC2016长春B (hdu 5912 Fraction)