题意:
给你一个字符串,只含'V', 'K', '?',其中'?’可能是任意这两个字符之一,问可能的循环节?(循环节不用整除N,只要满足s[i] = s[i + k])
题解:
找循环节,就是找所有公共前后缀长度。
现在有'?’ ,属于模糊匹配, 只能用FFT。
等于0的话就可以匹配,拆开是,做三次FFT即可。
(貌似不用做三次,别人都是做一次,我的做法常数比较大,贴一个别人的博客:
https://blog.csdn.net/v5zsq/article/details/79058756)
但是问题还没这么简单,
样例给出了一个反例。
5 V??VK
本来这组我们会算出有长度为2的循环节,但是不对。
v??能和 ?vk匹配,这是肯定的,但为什么不行呢?
注意到原串中间的那个?,既要等于V,又要等于K,这样就出矛盾了,所以不行。
抽象一下,其实问题在于:
有些?会匹配两个不同的字符。
什么时候会出现这样的情况?
当匹配的前后缀交叉的时候,中间的?假设下标为i,循环节长度为k,那么s[i] = s[i + k] , s[i - k] = s[i]。这时应该满足s[i] = s[i + 2k]才行,而且这本来就是循环节所应该满足的性质。
然而光判断2k是否是循环节这样还是有问题,再抽象一下,应该是判断所有k的倍数是否为循环节才行。
为什么?
中间的这些圆点应该都相同才行。
所以这题就这样啦。
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <bitset>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <cmath>
#include <ctime>
#ifdef LOCAL
#define debug(x) cout<<#x<<" = "<<(x)<<endl;
#else
#define debug(x) 1;
#endif
#define chmax(x,y) x=max(x,y)
#define chmin(x,y) x=min(x,y)
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
#define lowbit(x) x&-x
#define mp make_pair
#define pb push_back
#define fir first
#define sec second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, int> pii;
const ll MOD = 1e9 + 7;
const double PI = acos (-1.);
const double eps = 1e-10;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 262144 * 8 + 5;
char s[MAXN];
char t[MAXN];
//typedef complex<double> CP;
struct CP {
double x, y;
CP() {}
CP (double x, double y) : x (x), y (y) {}
inline double real() {
return x;
}
inline CP operator * (const CP& r) const {
return CP (x * r.x - y * r.y, x * r.y + y * r.x);
}
inline CP operator - (const CP& r) const {
return CP (x - r.x, y - r.y);
}
inline CP operator + (const CP& r) const {
return CP (x + r.x, y + r.y);
}
inline CP conj (const CP &r) {
return CP (r.x, -r.y);
}
};
CP a[MAXN], b[MAXN];
int r[MAXN], res[MAXN];
void fft_init (int nm, int k) {
for (int i = 0; i < nm; ++i) r[i] = (r[i >> 1] >> 1) | ( (i & 1) << (k - 1) );
}
void fft (CP ax[], int nm, int op) {
for (int i = 0; i < nm; ++i) if (i < r[i]) swap (ax[i], ax[r[i]]);
for (int h = 2, m = 1; h <= nm; h <<= 1, m <<= 1) { // 枚举长度
CP wn = CP (cos (op * 2 * PI / h), sin (op * 2 * PI / h) );
for (int i = 0; i < nm; i += h) { // 枚举所有长度为 h 的区间
CP w (1, 0); // 旋转因子
for (int j = i; j < i + m; ++j, w = w * wn) { // 枚举角度
CP t = w * ax[j + m]; // 蝴蝶操作
ax[j + m] = ax[j] - t;
ax[j] = ax[j] + t;
}
}
}
if (op == -1) for (int i = 0; i < nm; ++i) ax[i].x /= nm;
}
void trans (int ax[], int bx[], int n, int m, int mul) {
int nm = 1, k = 0;
while (nm < 2 * n || nm < 2 * m) nm <<= 1, ++k;
for (int i = 0; i < n; ++i) a[i] = CP (ax[i], 0);
for (int i = 0; i < m; ++i) b[i] = CP (bx[i], 0);
for (int i = n; i < nm; ++i) a[i] = CP (0, 0);
for (int i = m; i < nm; ++i) b[i] = CP (0, 0);
fft_init (nm, k);
fft (a, nm, 1);
fft (b, nm, 1);
for (int i = 0; i < nm; ++i) a[i] = a[i] * b[i];
fft (a, nm, -1);
nm = n + m - 1;
for (int i = 0; i < nm; ++i) res[i] += (int) (a[i].real() + 0.5) * mul;
}
int s1[MAXN], t1[MAXN];
int ans[MAXN];
int getid (char x) {
if (x == 'V') return 1;
if (x == 'K') return -1;
return 0;
}
int main() {
#ifdef LOCAL
freopen ("input.txt", "r", stdin);
#endif
int T;
cin >> T;
while (T--) {
int n;
scanf ("%d %s", &n, s);
for (int i = 0; i <= 2 * n; i++) res[i] = 0;
for (int i = 0; i < n; i++) {
s1[i] = getid (s[i]) * getid (s[i]) * getid (s[i]);
t1[i] = getid (s[i]);
}
reverse (t1, t1 + n);
trans (s1, t1, n, n, 1);
for (int i = 0; i < n; i++) {
s1[i] = getid (s[i]);
t1[i] = getid (s[i]) * getid (s[i]) * getid (s[i]);
}
reverse (t1, t1 + n);
trans (s1, t1, n, n, 1);
for (int i = 0; i < n; i++) {
s1[i] = getid (s[i]) * getid (s[i]);
t1[i] = getid (s[i]) * getid (s[i]);
}
reverse (t1, t1 + n);
trans (s1, t1, n, n, -2);
for (int i = 0; i <= n; i++) ans[i] = 0;
for (int i = 0; i < n; i++)
if (res[i] == 0) ans[n - i - 1] = 1;
ans[n] = 1;
vector<int> v;
for (int i = n; i >= 1; i--) {
for (int j = i + i; j <= n; j += i) ans[i] &= ans[j];
if (ans[i]) v.pb (i);
}
printf ("%d\n", v.size() );
reverse (v.begin(), v.end() );
for (int i : v) printf ("%d ", i);
puts ("");
}
return 0;
}