Codeforces 827E Rusty String - 快速傅裏葉變換 - 暴力
Grigory loves strings. Recently he found a metal strip on a loft. The strip had length n and consisted of letters "V" and "K". Unfortunately, rust has eaten some of the letters so that it‘s now impossible to understand which letter was written.
Grigory couldn‘t understand for a long time what these letters remind him of, so he became interested in the following question: if we put a letter "V
A period of a string is such an integer d from 1 to the length of the string that if we put the string shifted by d positions to the right on itself, then all overlapping letters coincide. For example, 3
There are several (at least one) test cases in the input. The first line contains single integer — the number of test cases.
There is an empty line before each test case. Each test case is described in two lines: the first line contains single integer n
It is guaranteed that the sum of lengths among all test cases doesn‘t exceed 5·105.
For hacks you can only use tests with one test case.
OutputFor each test case print two lines. In the first line print the number of possible periods after we replace each unreadable letter with "V" or "K". In the next line print all these values in increasing order.
Example input3output
5
V??VK
6
??????
4
?VK?
2Note
3 5
6
1 2 3 4 5 6
3
2 3 4
In the first test case from example we can obtain, for example, "VKKVK", which has periods 3 and 5.
In the second test case we can obtain "VVVVVV" which has all periods from 1 to 6.
In the third test case string "KVKV" has periods 2 and 4, and string "KVKK" has periods 3 and 4.
題目大意 給定一個只包含通配符‘?‘和‘v‘,‘K‘的串,詢問所有可能的循環節長度。
首先一個事實就是如果x是可能的循環節,那麽2x,3x也一定是。(證明是顯然的)
因此可以根據這個愉快的事實進行暴力(似乎出題人在題解的Comments中表示對數據出水了感到歉意)
思路大概就是暴力check如果可行就把它的倍數都標為可行的。
Code
1 /** 2 * Codeforces 3 * Problem#827E 4 * Accepted 5 * Time: 265ms 6 * Memory: 988k 7 */ 8 #include <bits/stdc++.h> 9 using namespace std; 10 typedef bool boolean; 11 12 const int lim = 5e5; 13 14 int n; 15 char str[lim + 1]; 16 boolean app[3]; 17 boolean able[lim + 1]; 18 19 inline void init() { 20 scanf("%d", &n); 21 gets(str); 22 gets(str); 23 } 24 25 inline boolean check(int len) { 26 for(int i = 0; i < len; i++) { 27 char should = str[i]; 28 for(int j = i + len; j < n; j += len) { 29 if(should != ‘?‘ && str[j] != ‘?‘ && should != str[j]) return false; 30 if(str[j] != ‘?‘) should = str[j]; 31 } 32 } 33 return true; 34 } 35 36 inline void solve() { 37 app[0] = app[1] = false; 38 for(int i = 0; i < n; i++) { 39 switch(str[i]) { 40 case ‘V‘: 41 app[0] = true; 42 break; 43 case ‘K‘: 44 app[1] = true; 45 break; 46 } 47 } 48 if(!app[0] && !app[1]) { 49 printf("%d\n", n); 50 for(int i = 1; i <= n; i++) 51 printf("%d%c", i, (i == n) ? (‘\n‘) : (‘ ‘)); 52 return; 53 } 54 int res = 0; //, cnt = 0; 55 for(int i = 1; i <= n; i++) 56 if(!able[i] && check(i))// && (++cnt)) 57 for(int j = i; j <= n; j += i) 58 res += !able[j], able[j] = true; 59 printf("%d\n", res); 60 for(int i = 1; i <= n; i++) 61 if(able[i]) { 62 printf("%d ", i); 63 able[i] = false; 64 } 65 putchar(‘\n‘); 66 // fprintf(stderr, "%dms counted %d times\n", clock(), cnt); 67 } 68 69 int T; 70 int main() { 71 scanf("%d", &T); 72 while(T--) { 73 init(); 74 solve(); 75 } 76 return 0; 77 }Rusty String(Brute force)
然後假設沒有這個通配符應該怎麽用bitset, 多項式乘法之類的做(因為每個位置除了通配符,只有V或K,而且因為有通配符的存在,所以KMP就不能抓過來用了)
首先根據KMP的思想,如果存在長度為k的循環節那麽存在長度為(n - k)的公共前後綴。
所以我們可以把這個串右移k位然後check,最後判一下特殊情況。
為了更快地進行check,所以,我們設A數組中A[I]為1當且僅當s[I] == ‘v‘,B[i]為1當且僅當s[i] == ‘K‘。
初步可行的條件是並且
然後為了能夠順利地進行下一步,我們設A‘[i] = A[n - i - 1]。於是你會發現兩邊A‘的下標和B的和是一個定值,而且範圍不相交。因此我們可以把A‘數組和B數組當成兩個多項式的系數數組,然後進行FFT。
最開始說的特殊情況是指類似於存在某一個i使得s[i] != s[i + 2k]並且s[i + k] == ‘?‘。
首先可以初步地將一些循環節判斷為不可行,對於看似沒有問題的循環節長度,我們還需要check它的倍數中有沒有被標記為不可行的,如果存在它就不可行(這樣做的話就可以把以上的特殊情況處理掉)。
因為數據沒有卡暴力,我深深地感受到什麽是暴力碾壓正解。
Code
1 /** 2 * Codeforces 3 * Problem#827 4 * Accepted 5 * Time: 311ms 6 * Memory: 68200k 7 */ 8 #include <bits/stdc++.h> 9 using namespace std; 10 typedef bool boolean; 11 12 template<typename T> 13 class Complex { 14 public: 15 T r; 16 T v; 17 18 Complex(T r = 0, T v = 0):r(r), v(v) { } 19 20 Complex operator + (Complex b) { 21 return Complex(r + b.r, v + b.v); 22 } 23 24 Complex operator - (Complex b) { 25 return Complex(r - b.r, v - b.v); 26 } 27 28 Complex operator * (Complex b) { 29 return Complex(r * b.r - v * b.v, r * b.v + v * b.r); 30 } 31 32 Complex operator / (double x) { 33 return Complex(r / x, v / x); 34 } 35 }; 36 37 const int N = 1 << 21; 38 const double pi = acos(-1); 39 const double eps = 0.5; 40 41 inline void Rader(Complex<double> *f, int len) { 42 for(int i = 1, j = len >> 1, k; i < len - 1; i++) { 43 if(i < j) 44 swap(f[i], f[j]); 45 for(k = len >> 1; j >= k; j -= k, k >>= 1); 46 if(j < k) 47 j += k; 48 } 49 } 50 51 inline void fft(Complex<double> *f, int len, int sign) { 52 Rader(f, len); 53 for(int l = 2; l <= len; l <<= 1) { 54 Complex<double> wn(cos(2 * pi / l), sin(2 * pi * sign / l)), u, v; 55 int hl = l >> 1; 56 for(int i = 0; i < len; i += l) { 57 Complex<double> w(1, 0); 58 for(int j = 0; j < hl; j++, w = w * wn) { 59 u = f[i + j], v = w * f[i + j + hl]; 60 f[i + j] = u + v, f[i + j + hl] = u - v; 61 } 62 } 63 } 64 if(sign == -1) 65 for(int i = 0; i < len; i++) 66 f[i] = f[i] / len; 67 } 68 69 int n, len; 70 char str[500005]; 71 Complex<double> A[N], B[N]; 72 73 inline void init() { 74 scanf("%d", &n); 75 gets(str); 76 gets(str); 77 for(len = 1; len < (n << 1); len <<= 1); 78 memset(A, 0, sizeof(Complex<double>) * (len + 1)); 79 memset(B, 0, sizeof(Complex<double>) * (len + 1)); 80 for(int i = 0; i < n; i++) { 81 if(str[i] == ‘V‘) 82 A[n - i - 1].r = 1; 83 else if(str[i] == ‘K‘) 84 B[i].r = 1; 85 } 86 } 87 88 boolean bad[N]; 89 int res = 0; 90 inline void solve() { 91 fft(A, len, 1); 92 fft(B, len, 1); 93 for(int i = 0; i < len; i++) A[i] = A[i] * B[i]; 94 fft(A, len, -1); 95 memset(bad, false, sizeof(boolean) * (n + 1)); 96 // for(int i = 1; i < n; i++) 97 // if(A[n - i - 1].r >= eps || A[n + i - 1].r >= eps) 98 // bad[i] = true; 99 for(int i = 0; i < len; i++) 100 if(A[i].r >= eps) 101 bad[abs(i - n + 1)] = true; 102 for(int i = 1; i < n; i++) 103 if(!bad[i]) 104 for(int j = i << 1; j < n; j += i) 105 if(bad[j]) { 106 bad[i] = true; 107 break; 108 } 109 int res = 0; 110 for(int i = 1; i <= n; i++) 111 if(!bad[i]) 112 res++; 113 printf("%d\n", res); 114 for(int i = 1; i <= n; i++) { 115 if(!bad[i]) 116 printf("%d ", i); 117 } 118 putchar(‘\n‘); 119 } 120 121 int T; 122 int main() { 123 scanf("%d", &T); 124 while(T--) { 125 init(); 126 solve(); 127 } 128 return 0; 129 }
Codeforces 827E Rusty String - 快速傅裏葉變換 - 暴力