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

 /**
* Codeforces
* Problem#827E
* Accepted
* Time: 265ms
* Memory: 988k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; const int lim = 5e5; int n;
char str[lim + ];
boolean app[];
boolean able[lim + ]; inline void init() {
scanf("%d", &n);
gets(str);
gets(str);
} inline boolean check(int len) {
for(int i = ; i < len; i++) {
char should = str[i];
for(int j = i + len; j < n; j += len) {
if(should != '?' && str[j] != '?' && should != str[j]) return false;
if(str[j] != '?') should = str[j];
}
}
return true;
} inline void solve() {
app[] = app[] = false;
for(int i = ; i < n; i++) {
switch(str[i]) {
case 'V':
app[] = true;
break;
case 'K':
app[] = true;
break;
}
}
if(!app[] && !app[]) {
printf("%d\n", n);
for(int i = ; i <= n; i++)
printf("%d%c", i, (i == n) ? ('\n') : (' '));
return;
}
int res = ; //, cnt = 0;
for(int i = ; i <= n; i++)
if(!able[i] && check(i))// && (++cnt))
for(int j = i; j <= n; j += i)
res += !able[j], able[j] = true;
printf("%d\n", res);
for(int i = ; i <= n; i++)
if(able[i]) {
printf("%d ", i);
able[i] = false;
}
putchar('\n');
// fprintf(stderr, "%dms counted %d times\n", clock(), cnt);
} int T;
int main() {
scanf("%d", &T);
while(T--) {
init();
solve();
}
return ;
}

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

 /**
* Codeforces
* Problem#827
* Accepted
* Time: 311ms
* Memory: 68200k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; template<typename T>
class Complex {
public:
T r;
T v; Complex(T r = , T v = ):r(r), v(v) { } Complex operator + (Complex b) {
return Complex(r + b.r, v + b.v);
} Complex operator - (Complex b) {
return Complex(r - b.r, v - b.v);
} Complex operator * (Complex b) {
return Complex(r * b.r - v * b.v, r * b.v + v * b.r);
} Complex operator / (double x) {
return Complex(r / x, v / x);
}
}; const int N = << ;
const double pi = acos(-);
const double eps = 0.5; inline void Rader(Complex<double> *f, int len) {
for(int i = , j = len >> , k; i < len - ; i++) {
if(i < j)
swap(f[i], f[j]);
for(k = len >> ; j >= k; j -= k, k >>= );
if(j < k)
j += k;
}
} inline void fft(Complex<double> *f, int len, int sign) {
Rader(f, len);
for(int l = ; l <= len; l <<= ) {
Complex<double> wn(cos( * pi / l), sin( * pi * sign / l)), u, v;
int hl = l >> ;
for(int i = ; i < len; i += l) {
Complex<double> w(, );
for(int j = ; j < hl; j++, w = w * wn) {
u = f[i + j], v = w * f[i + j + hl];
f[i + j] = u + v, f[i + j + hl] = u - v;
}
}
}
if(sign == -)
for(int i = ; i < len; i++)
f[i] = f[i] / len;
} int n, len;
char str[];
Complex<double> A[N], B[N]; inline void init() {
scanf("%d", &n);
gets(str);
gets(str);
for(len = ; len < (n << ); len <<= );
memset(A, , sizeof(Complex<double>) * (len + ));
memset(B, , sizeof(Complex<double>) * (len + ));
for(int i = ; i < n; i++) {
if(str[i] == 'V')
A[n - i - ].r = ;
else if(str[i] == 'K')
B[i].r = ;
}
} boolean bad[N];
int res = ;
inline void solve() {
fft(A, len, );
fft(B, len, );
for(int i = ; i < len; i++) A[i] = A[i] * B[i];
fft(A, len, -);
memset(bad, false, sizeof(boolean) * (n + ));
// for(int i = 1; i < n; i++)
// if(A[n - i - 1].r >= eps || A[n + i - 1].r >= eps)
// bad[i] = true;
for(int i = ; i < len; i++)
if(A[i].r >= eps)
bad[abs(i - n + )] = true;
for(int i = ; i < n; i++)
if(!bad[i])
for(int j = i << ; j < n; j += i)
if(bad[j]) {
bad[i] = true;
break;
}
int res = ;
for(int i = ; i <= n; i++)
if(!bad[i])
res++;
printf("%d\n", res);
for(int i = ; i <= n; i++) {
if(!bad[i])
printf("%d ", i);
}
putchar('\n');
} int T;
int main() {
scanf("%d", &T);
while(T--) {
init();
solve();
}
return ;
}

Codeforces 827E Rusty String - 快速傅里叶变换 - 暴力的更多相关文章

  1. CF 827E Rusty String FFT

    传送门 如果没有碍事的?的话,判定字符串的循环节直接用KMP的失配数组就可以搞定.现在有了碍事的?,我们就需要考虑更通用的算法. 考虑KMP失配数组判定字符串循环节的本质,发现判定\(k\)是否为字符 ...

  2. 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/常用套路【入门】

    原文链接https://www.cnblogs.com/zhouzhendong/p/Fast-Fourier-Transform.html 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/ ...

  3. 【知识总结】快速傅里叶变换(FFT)

    这可能是我第五次学FFT了--菜哭qwq 先给出一些个人认为非常优秀的参考资料: 一小时学会快速傅里叶变换(Fast Fourier Transform) - 知乎 小学生都能看懂的FFT!!! - ...

  4. 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT)

    再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT) 目录 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Blueste ...

  5. 快速傅里叶变换FFT& 数论变换NTT

    相关知识 时间域上的函数f(t)经过傅里叶变换(Fourier Transform)变成频率域上的F(w),也就是用一些不同频率正弦曲线的加 权叠加得到时间域上的信号. \[ F(\omega)=\m ...

  6. 快速傅里叶变换(FFT)

    扯 去北京学习的时候才系统的学习了一下卷积,当时整理了这个笔记的大部分.后来就一直放着忘了写完.直到今天都腊月二十八了,才想起来还有个FFT的笔记没整完呢.整理完这个我就假装今年的任务全都over了吧 ...

  7. 51Nod 快速傅里叶变换题集选刷

    打开51Nod全部问题页面,在右边题目分类中找到快速傅里叶变换,然后按分值排序,就是本文的题目顺序. 1.大数乘法问题 这个……板子就算了吧. 2.美妙的序列问题 长度为n的排列,且满足从中间任意位置 ...

  8. 快速傅里叶变换FFT / NTT

    目录 FFT 系数表示法 点值表示法 复数 DFT(离散傅里叶变换) 单位根的性质 FFT(快速傅里叶变换) IFFT(快速傅里叶逆变换) NTT 阶 原根 扩展知识 FFT 参考blog: 十分简明 ...

  9. 快速傅里叶变换(FFT)相关内容汇总

    (原稿:https://paste.ubuntu.com/p/yJNsn3xPt8/) 快速傅里叶变换,是求两个多项式卷积的算法,其时间复杂度为$O(n\log n)$,优于普通卷积求法,且根据有关证 ...

随机推荐

  1. echarts实现全国地图

    1.首先我没有按需引入echarts,我是全局引入的,所以说在node_modules中有 这个china,你只需要在你的页面引入即可 但是按需引入echarts 的 项目中node_modules中 ...

  2. PHP 函数 ignore_user_abort()详解笔记

     定义和用法 ignore_user_abort()函数设置与客户机断开是否会终止脚本的执行  语法 ignore_user_abort(setting) 参数 描述 setting 可选.如果设置为 ...

  3. node.js连接本地数据库及json返回数据

    新建一个文件夹node.js,目录下打开命令初始化一下 cnpm init 然后下载express框架 cnpm install express --save 接着下载数据库的依赖 cnpm inst ...

  4. Centos 6.5初始化配置

    安装好centos 6.5 # -*- coding:utf-8 -*- import win32api import time import os from Tkinter import * are ...

  5. C-Cow Sorting (置换群, 数学)

    Farmer John's N (1 ≤ N ≤ 10,000) cows are lined up to be milked in the evening. Each cow has a uniqu ...

  6. java 使用jacob把word转pdf

    一.使用前要下载必要包及文件 链接: https://pan.baidu.com/s/1nvutQxb 密码: qgpi 二.引包和dll文件 1.引包:eclipse引包就不用说了,idea引包步骤 ...

  7. 4.7 引入NULL对象

    [1]引入NULL对象范例 Book.h #ifndef _BOOK_H #define _BOOK_H #include <string> using namespace std; cl ...

  8. 蒙特卡洛(Monte Carlo)法求定积分

    https://blog.csdn.net/baimafujinji/article/details/53869358

  9. 最小二乘法的Java实现

    最小二乘法原理十分简单,这里不再赘述.对于预测公式y' = a * x + b,最优解如下 double a = Sxy / Sxx; double b = yAvg - a * xAvg; doub ...

  10. 这份书单,给那些想学Hadoop大数据、人工智能的人

    一.简单科普类 (文末附下载链接) 1.<人工智能:李开复谈AI如何重塑个人.商业与社会的未来图谱2> 作者:李开复,王咏刚 推荐理由:文章写得一般,但李开复和王永刚老师总结的还可以,算国 ...