1. 程式人生 > >Codeforces 827E Rusty String - 快速傅裏葉變換 - 暴力

Codeforces 827E Rusty String - 快速傅裏葉變換 - 暴力

後綴 graph pro 問題 luci sid alt image .com

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

" or "K" on each unreadable position, which values can the period of the resulting string be equal to?

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

and 5 are periods of "VKKVK".

Input

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

(1 ≤ n ≤ 5·105) — the length of the string, the second line contains the string of length n, consisting of letters "V", "K" and characters "?". The latter means the letter on its position is unreadable.

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.

Output

For 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 input
3

5
V??VK

6
??????

4
?VK?
output
2
3 5
6
1 2 3 4 5 6
3
2 3 4
Note

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 - 快速傅裏葉變換 - 暴力