Codeforces 827E Rusty String - 快速傅里叶变换 - 暴力

Posted 阿波罗2003

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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" 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 - 快速傅里叶变换 - 暴力的主要内容,如果未能解决你的问题,请参考以下文章

Rusty String

无法安装 web3。我收到一条错误消息,说版本不满足要求 rusty-rlp

Educational Codeforces Round 72 (Rated for Div. 2)

Codeforces 96A

Codeforces 112A

codeforces 494a//Treasure// Codeforces Round #282(Div. 1)