传送门

如果没有碍事的?的话,判定字符串的循环节直接用KMP的失配数组就可以搞定。现在有了碍事的?,我们就需要考虑更通用的算法。

考虑KMP失配数组判定字符串循环节的本质,发现判定\(k\)是否为字符串的循环节等价于判定字符串在右移\(k\)位后能否和原字符串匹配(只考虑二者重叠的部分)。

我们不妨先把?直接看成一个可以匹配任何字符的通配符,而解决带通配符的字符串匹配问题的一个算法就是FFT

(以下默认下标为\(0\)~\(n-1\))

设字符串为\(s\),因为字符集只有\(2\),不妨直接枚举不能匹配的两种情况。定义\(a_i=[s_i='V']\),\(b_i=[s_i='K']\),另一种情况只需要把定义反过来就行了。

再定义一个数组

\[\begin{align}c_i=\sum_{j=0}^{n-1}a_{i+j}b_j\end{align}
\]

(另一种情况式子是一样的)

发现\(s\)右移\(i\)位后能和原串匹配当且仅当两种情况的\(c_i\)都为\(0\)。

而上面的式子把\(\{a_i\}\)反转后就是

\[\begin{align}c_i=\sum_{j=0}^{n-1}a^R_{n-i-j-1}b_{j}\end{align}=\left(a^R*b\right)_{n-i-1}
\]

跑两遍卷积即可。

然而还是会发现一些问题……从样例就能看出来,这里的?其实并不是通配符,因为在判定循环节时一个?在不同的位置必须代表相同的字符(可能有点抽象,参见第一组样例中2为什么可以匹配但不是循环节)。

然而这个问题其实并不棘手。我们都知道如果一个数真的是循环节那么它的所有倍数也一定是循环节,所以对于那些\(c_i\)为\(00\)的位置再判断一下它的倍数是否也都满足\(c_i=0\)就行了。

(完整证明参见官方题解)

这一步的复杂度是\(O(n\log n)\)的,不会影响到总复杂度。

另外,考虑到问题的特殊性,其实不必跑两遍卷积,任意跑其中一种情况即可,两种情况的\(c_i\)分别是\(\left(a^R*b\right)_{n-i-1}\)和\(+\left(a^R*b\right)_{n+i-1}\)(可以从两种情况的对称性的角度理解)。

(我比较懒写的是NTT)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1048600,p=998244353,g=3;
void NTT(int*,int,int);
int qpow(int,int);
char s[maxn];
bool ans[maxn];
int T,n,A[maxn],B[maxn];
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%s",&n,s);
int N=1;
while(N<(n<<1))N<<=1;
memset(A,0,sizeof(int)*N);
memset(B,0,sizeof(int)*N);
for(int i=0;i<n;i++){
if(s[i]=='V')A[n-i-1]=1;
else if(s[i]=='K')B[i]=1;
}
NTT(A,N,1);
NTT(B,N,1);
for(int i=0;i<N;i++)A[i]=(long long)A[i]*B[i]%p;
NTT(A,N,-1);
int cnt=0;
for(int i=1;i<=n;i++){
ans[i]=true;
for(int j=i;j<=n;j+=i)ans[i]&=!(A[n-j-1]+A[n+j-1]);
cnt+=ans[i];
}
printf("%d\n",cnt);
for(int i=1;i<=n;i++)
if(ans[i]){
printf("%d",i);
if(--cnt)printf(" ");
}
printf("\n");
}
return 0;
}
void NTT(int *A,int n,int tp){
for(int i=1,j=0,k;i<n-1;i++){
k=n;
do j^=(k>>=1);while(j<k);
if(i<j)swap(A[i],A[j]);
}
for(int k=2;k<=n;k<<=1){
int wn=qpow(g,tp>0?(p-1)/k:p-1-(p-1)/k);
for(int i=0;i<n;i+=k){
int w=1;
for(int j=0;j<(k>>1);j++,w=(long long)w*wn%p){
int a=A[i+j],b=(long long)w*A[i+j+(k>>1)]%p;
A[i+j]=a+b;
if(A[i+j]>=p)A[i+j]-=p;
A[i+j+(k>>1)]=a-b;
if(A[i+j+(k>>1)]<0)A[i+j+(k>>1)]+=p;
}
}
}
if(tp<0){
int inv=qpow(n,p-2);
for(int i=0;i<n;i++)A[i]=(long long)A[i]*inv%p;
}
}
int qpow(int a,int b){
int ans=1;
for(;b;b>>=1,a=(long long)a*a%p)if(b&1)ans=(long long)ans*a%p;
return ans;
}

CF 827E Rusty String FFT的更多相关文章

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

    Grigory loves strings. Recently he found a metal strip on a loft. The strip had length n and consist ...

  2. 【CF827E】Rusty String 调和级数+FFT

    [CF827E]Rusty String 题意:给你一个01串,其中部分字符是'?',?可以是0或1,求所有可能的d,满足存在一种可能得到的01串,在向右移动d格后与自己相同. $n\le 5\tim ...

  3. E. Rusty String

    E. Rusty String time limit per test 3 seconds memory limit per test 512 megabytes input standard inp ...

  4. 【题解】Rusty String [CF827E]

    [题解]Rusty String [CF827E] 传送门:\(\text{Rusty String}\) \(\text{[CF827E]}\) [题目描述] 多组数据,每组数据给出一个由 \(V, ...

  5. CF 1131 E. String Multiplication

    E. String Multiplication 题意 分析: 从后往前考虑字符串变成什么样子. 设$S_i = p_1 \cdot p_2 \dots p_{i}$,最后一定是$S_{n - 1} ...

  6. CF 1003B Binary String Constructing 【构造/找规律/分类讨论】

    You are given three integers a, b and x. Your task is to construct a binary string s of length n=a+b ...

  7. CF #541 E. String Multiplication

    题意: 给定一系列字符串,每次都是后一个字符串和前面的融合,这个融合操作就是原来的串分成独立的,然后把新串插入到这些空格中.问最后,最长的相同连续的长度. 思路: 这道题可以贪心的来,我们压缩状态,记 ...

  8. CF 1140B Good String

    Description You have a string ss of length nn consisting of only characters > and <. You may d ...

  9. 【CF 710F】String Set Queries

    在校内OJ上A了,没有加强制在线的东西..不放链接了. 这道题题意是维护一个字符串集合,支持三种操作: 1.加字符串 2.删字符串 3.查询集合中的所有字符串在给出的模板串中出现的次数 操作数\(m ...

随机推荐

  1. 企业IM (或业务系统)web api的json格式设计思考(原创)

    在企业IM开发中,经常用到和业务系统的数据交换,在中国企业最常见的比如组织架构变更,一般在客户端加密保存了组织架构树(便于快速的查询和树展示),当HR或OA或AD域这些管控企业组织架构的数据发生改变, ...

  2. Storm系列二: Storm拓扑设计

    Storm系列二: Storm拓扑设计 在本篇中,我们就来根据一个案例,看看如何去设计一个拓扑, 如何分解问题以适应Storm架构,同时对Storm拓扑内部的并行机制会有一个基本的了解. 本章代码都在 ...

  3. rabbitmq系列三 之发布/订阅

    1.发布/订阅 在上篇教程中,我们搭建了一个工作队列,每个任务只分发给一个工作者(worker).在本篇教程中,我们要做的跟之前完全不一样 —— 分发一个消息给多个消费者(consumers).这种模 ...

  4. 用Python玩转数据第六周——高级数据处理与可视化

    1.matplotlib中有两个模块,pyplot和pylab import matplotlib.pyplot as plt  ///plt.plot(x,y) import pylab as pl ...

  5. Delphi获取IdHTTP1.Get(url)的返回参数

    var   ss: TStringStream; begin   ss := TStringStream.Create('');   idHTTP1.get(url, ss);   ss.Positi ...

  6. (转)Python中集合(set)的基本操作以及一些常见的用法

    原文:http://blog.51cto.com/10616534/1944841 Python除了List.Tuple.Dict等常用数据类型外,还有一种数据类型叫做集合(set),集合的最大特点是 ...

  7. Android 开发工具类 03_HttpUtils

    Http 请求的工具类: 1.异步的 Get 请求: 2.异步的 Post 请求: 3.Get 请求,获得返回数据: 4.向指定 URL 发送 POST方法的请求. import java.io.Bu ...

  8. IntelliJ IDEA使用心得之问题篇;

    在使用IDEA的时候,难免会遇到一些问题,总结下来,一是备忘,而是分享. 1.IDEA代码编辑区无法编辑? 当系统时间被调整到当前时间以前时会导致IDEA无法编辑,有3中解决方案:1)重启IDEA:( ...

  9. C/C++中的static

    一.静态全局变量 理解static关键字之前首先回顾一下C/C++程序的在内存中的分配情况.从低地址到高地址依次分为:代码区.全局数据区.堆区.栈区.函数之外的全局变量和静态变量(包括全局变量和静态变 ...

  10. DirectorySearcher.Filter 属性(转)

    获取或设置一个值,该值的轻型目录访问协议 (LDAP) 格式筛选器字符串. 更多信息见:http://www.cnblogs.com/zhongweiv/archive/2013/01/05/ad_s ...