agc031
T1 题意:给你一个串,求所有子序列个数,满足没有相同字符。1e5,2s。
解:考虑一个合法的子序列。其中每个字母的出现位置都有(出现次数)种选择。还可以不选,要 + 1。
然后乘起来就做完了。如果变成子串的话更简单,每个位置为开头的长度不会超过26,直接暴力。本质不同子串就开个hash池判重。
本质不同子序列......不会。
1 #include <bits/stdc++.h> 2 3 const int N = 100010, MO = 1e9 + 7; 4 5 char str[N]; 6 int bin[26]; 7 8 int main() { 9 int n; 10 scanf("%d", &n); 11 scanf("%s", str); 12 for(int i = 0; i < n; i++) { 13 bin[str[i] - 'a']++; 14 } 15 int ans = 1; 16 for(int i = 0; i < 26; i++) { 17 ans = 1ll * ans * (bin[i] + 1) % MO; 18 } 19 printf("%d", (ans + MO - 1) % MO); 20 21 return 0; 22 }
T2 题意:给你一个序列,可以若干次选择两个相同的数字,使其之间的数字全部变成这个数字。求最终可能的序列总数。2e5,2s。
解:发现选出来的序列一定是一些相离的,所以可以DP,设f[i]表示前i位可能的方案总数。那么第i位可能和前面任一个相同的数匹配,f[i] += f[j - 1]。
同时也可能不匹配,相当于自己跟自己匹配。我们要对所有ai等于一个数的DP值求和,直接开个桶。
发现有连续相同的数的时候会挂,把它们缩起来。
1 #include <bits/stdc++.h> 2 3 typedef long long LL; 4 const int N = 200010, MO = 1e9 + 7; 5 6 int a[N], bin[N], f[N]; 7 8 int main() { 9 10 int n; 11 scanf("%d", &n); 12 for(int i = 1; i <= n; i++) { 13 scanf("%d", &a[i]); 14 if(a[i] == a[i - 1]) { 15 i--; 16 n--; 17 } 18 } 19 f[0] = 1; 20 for(int i = 1; i <= n; i++) { 21 (bin[a[i]] += f[i - 1]) %= MO; 22 f[i] = bin[a[i]]; 23 } 24 printf("%d", f[n]); 25 26 return 0; 27 }
T3 题意:求一个1 ~ 2n的排列,满足第一个数是A,最后一个数是B,且相邻两个数的二进制只有一位不同。17,2s。
解:猜一下结论,如果A和B二进制下不同的位数有偶数个,那么一定无解。其余的有解。
因为有个头尾的限制,所以我们直接暴力分治。
每次讨论A和B最高位是否相同。相同的话就先把最高位变一下填2n-1个,然后变回来填后面的。
不同的话就前2n-1个最高位从A,后面最高位从B。
1 /** 2 * There is a start and there is no end in the space. ---Infinity. 3 * It ruins and goes though there is also a start in stars. ---Finite. 4 * Only the man who has wisdom can read the most foolish one from the history. 5 * Fishes living in the sea doesn't know the life in the land. 6 * It also ruins and goes if they have wisdom. 7 * It funnier that man exceeds the speed of light than fish start living in the land. 8 * It can be said that this is an final ultimatum from the god to the people who can fight. 9 * 10 * Steins;Gate 11 */ 12 13 #include <bits/stdc++.h> 14 15 const int N = 150000; 16 17 int n, A, B, p[N], top, now, lm, same, dt; 18 19 inline void out(int x) { 20 for(int i = 0; i < n; i++) { 21 printf("%d", (x >> i) & 1); 22 } 23 return; 24 } 25 26 inline int cal(int x) { 27 int ans = 0; 28 while(x) { 29 ans++; 30 x -= x & (-x); 31 } 32 return ans; 33 } 34 35 inline int Abs(int x) { 36 return x < 0 ? -x : x; 37 } 38 39 inline int First(int x) { 40 for(int i = n - 1; i >= 0; i--) { 41 if((x >> i) & 1) return 1 << i; 42 } 43 return 0; 44 } 45 46 void solve(int n, int l, int r, int a, int b) { 47 if(n == 1) { 48 p[l] = a; 49 p[r] = b; 50 return; 51 } 52 int mid = (l + r) >> 1, nexlm = (1 << (n - 1)) - 1; 53 if(((a >> (n - 1)) & 1) == ((b >> (n - 1)) & 1)) { 54 solve(n - 1, mid + 1, r, a & nexlm, b & nexlm); 55 if((a >> (n - 1)) & 1) { 56 for(int i = mid + 1; i <= r; i++) { 57 p[i] |= 1 << (n - 1); 58 } 59 p[l] = p[mid + 1]; 60 solve(n - 1, l + 1, mid + 1, a & nexlm, p[mid + 2] & nexlm); 61 } 62 else { 63 p[l] = p[mid + 1]; 64 solve(n - 1, l + 1, mid + 1, a & nexlm, p[mid + 2] & nexlm); 65 for(int i = l + 1; i <= mid + 1; i++) { 66 p[i] |= (1 << (n - 1)); 67 } 68 } 69 } 70 else { 71 solve(n - 1, l, mid, a & nexlm, (b & nexlm) ^ 1); 72 if((a >> (n - 1)) & 1) { 73 for(int i = l; i <= mid; i++) { 74 p[i] |= 1 << (n - 1); 75 } 76 solve(n - 1, mid + 1, r, p[mid] & nexlm, b & nexlm); 77 } 78 else { 79 solve(n - 1, mid + 1, r, p[mid] & nexlm, b & nexlm); 80 for(int i = mid + 1; i <= r; i++) { 81 p[i] |= 1 << (n - 1); 82 } 83 } 84 } 85 return; 86 } 87 88 int main() { 89 90 scanf("%d%d%d", &n, &A, &B); 91 lm = (1 << n) - 1, dt = A ^ B, same = dt ^ lm; 92 93 if((cal(dt) & 1) == 0) { 94 puts("NO"); 95 } 96 else { 97 puts("YES"); 98 solve(n, 0, lm, A, B); 99 for(int i = 0; i <= lm; i++) { 100 //out(p[i]); printf(" "); 101 printf("%d ", p[i]); 102 //puts(""); 103 } 104 } 105 return 0; 106 }
T4 题意:给定两个排列a和b,定义f(a, b)是一个排列,满足第ai个位置上的数是bi。定义A为一个序列,每个元素是一个排列,且A1 = a, A2 = b, Ai = f(Ai-2, Ai-1),求Ak。10w,1e9,2s。
解:神仙...
对于两个排列a和b,定义ab[i] = a[b[i]], a-1[a[i]] = i。于是我们把A的前几项写出来,然后瞎搞一通,就能发现一个奇妙的规律orz...
直接上官方题解了。
我们把A的每一个元素拆成sts-1的形式。然后发现si+6 = siba-1b-1a,是个等比数列。然后t是6个一循环的。
于是我们求出ba-1b-1a的k / 6次方就做完了......注意到求一个排列的k次方只需找出每个元素所在的环,然后跳(k % 环长)步即可。
1 #include <bits/stdc++.h> 2 3 const int N = 100010; 4 5 int a[N], b[N], c[N], d[N], A[N], n, k, vis[N], B[N], dis[N], C[N], D[N]; 6 int t1[2][N], t2[2][N], t3[2][N], ans[7][N]; 7 std::vector<int> v[N]; 8 9 inline int Find(int x, int t) { 10 int loop = v[vis[x]].size() - 1; 11 t = (t + dis[x]) % loop; 12 return v[vis[x]][t]; 13 } 14 15 int main() { 16 17 scanf("%d%d", &n, &k); 18 k--; 19 for(int i = 1; i <= n; i++) scanf("%d", &a[i]); 20 for(int i = 1; i <= n; i++) scanf("%d", &b[i]); 21 22 /// get A c = b-1 d = a-1 23 for(int i = 1; i <= n; i++) { 24 c[b[i]] = i; 25 d[a[i]] = i; 26 } 27 /*for(int i = 1; i <= n; i++) { 28 printf("%d ", c[i]); 29 } 30 puts(""); 31 for(int i = 1; i <= n; i++) { 32 printf("%d ", d[i]); 33 } 34 puts("");*/ 35 for(int i = 1; i <= n; i++) { 36 A[i] = b[d[c[ a[i] ]]]; 37 } 38 int t = k / 6; 39 //printf("t = %d \n", t); 40 /// get B = A^t 41 for(int i = 1; i <= n; i++) { 42 if(vis[i]) continue; 43 /// !vis[i] 44 int j = i; 45 v[i].push_back(i); 46 do { 47 j = A[j]; 48 dis[j] = v[i].size(); 49 vis[j] = i; 50 v[i].push_back(j); 51 } while(j != i); 52 dis[i] = 0; 53 } 54 for(int i = 1; i <= n; i++) { 55 B[i] = t ? Find(i, t) : i; 56 } 57 58 /*printf("vis : \n"); 59 for(int i = 1; i <= n; i++) { 60 printf("%d ", vis[i]); 61 } 62 puts(""); 63 64 printf("A : \n"); 65 for(int i = 1; i <= n; i++) { 66 printf("%d ", A[i]); 67 } 68 puts("");*/ 69 70 memcpy(t1[0] + 1, B + 1, n * sizeof(int)); 71 memcpy(t1[1] + 1, B + 1, n * sizeof(int)); 72 memcpy(t2[0] + 1, a + 1, n * sizeof(int)); 73 memcpy(t2[1] + 1, b + 1, n * sizeof(int)); 74 for(int i = 1; i <= n; i++) { 75 t3[0][t1[0][i]] = i; 76 t3[1][t1[1][i]] = i; 77 } 78 79 for(int i = 1; i <= n; i++) { 80 ans[0][i] = t1[0][t2[0][t3[0][i]]]; 81 ans[1][i] = t1[1][t2[1][t3[1][i]]]; 82 } 83 t = k % 6; 84 //printf("t = %d \n", t); 85 for(int i = 2; i <= t; i++) { 86 for(int j = 1; j <= n; j++) { 87 ans[i][ans[i - 2][j]] = ans[i - 1][j]; 88 } 89 } 90 91 /*puts(""); 92 for(int i = 0; i <= 1; i++) { 93 for(int j = 1; j <= n; j++) { 94 printf("%d ", ans[i][j]); 95 } 96 puts(""); 97 } 98 puts("");*/ 99 100 for(int i = 1; i <= n; i++) { 101 printf("%d ", ans[t][i]); 102 } 103 104 return 0; 105 }