CF 827E Rusty String FFT
如果没有碍事的?的话,判定字符串的循环节直接用KMP的失配数组就可以搞定。现在有了碍事的?,我们就需要考虑更通用的算法。
考虑KMP失配数组判定字符串循环节的本质,发现判定\(k\)是否为字符串的循环节等价于判定字符串在右移\(k\)位后能否和原字符串匹配(只考虑二者重叠的部分)。
我们不妨先把?直接看成一个可以匹配任何字符的通配符,而解决带通配符的字符串匹配问题的一个算法就是FFT。
(以下默认下标为\(0\)~\(n-1\))
设字符串为\(s\),因为字符集只有\(2\),不妨直接枚举不能匹配的两种情况。定义\(a_i=[s_i='V']\),\(b_i=[s_i='K']\),另一种情况只需要把定义反过来就行了。
再定义一个数组
\]
(另一种情况式子是一样的)
发现\(s\)右移\(i\)位后能和原串匹配当且仅当两种情况的\(c_i\)都为\(0\)。
而上面的式子把\(\{a_i\}\)反转后就是
\]
跑两遍卷积即可。
然而还是会发现一些问题……从样例就能看出来,这里的?其实并不是通配符,因为在判定循环节时一个?在不同的位置必须代表相同的字符(可能有点抽象,参见第一组样例中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的更多相关文章
- Codeforces 827E Rusty String - 快速傅里叶变换 - 暴力
Grigory loves strings. Recently he found a metal strip on a loft. The strip had length n and consist ...
- 【CF827E】Rusty String 调和级数+FFT
[CF827E]Rusty String 题意:给你一个01串,其中部分字符是'?',?可以是0或1,求所有可能的d,满足存在一种可能得到的01串,在向右移动d格后与自己相同. $n\le 5\tim ...
- E. Rusty String
E. Rusty String time limit per test 3 seconds memory limit per test 512 megabytes input standard inp ...
- 【题解】Rusty String [CF827E]
[题解]Rusty String [CF827E] 传送门:\(\text{Rusty String}\) \(\text{[CF827E]}\) [题目描述] 多组数据,每组数据给出一个由 \(V, ...
- CF 1131 E. String Multiplication
E. String Multiplication 题意 分析: 从后往前考虑字符串变成什么样子. 设$S_i = p_1 \cdot p_2 \dots p_{i}$,最后一定是$S_{n - 1} ...
- 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 ...
- CF #541 E. String Multiplication
题意: 给定一系列字符串,每次都是后一个字符串和前面的融合,这个融合操作就是原来的串分成独立的,然后把新串插入到这些空格中.问最后,最长的相同连续的长度. 思路: 这道题可以贪心的来,我们压缩状态,记 ...
- CF 1140B Good String
Description You have a string ss of length nn consisting of only characters > and <. You may d ...
- 【CF 710F】String Set Queries
在校内OJ上A了,没有加强制在线的东西..不放链接了. 这道题题意是维护一个字符串集合,支持三种操作: 1.加字符串 2.删字符串 3.查询集合中的所有字符串在给出的模板串中出现的次数 操作数\(m ...
随机推荐
- 不再需要ImageOle或DynamicGifCtl,.NET实现IM编辑控件
多年前写过一篇文章<C# 实现IM聊天信息输入显示控件(1)-显示GIF动画图片>,主要是使用ActiveX控件实现RichTextBox插入gif动画图片,包括使用QQ的ImageOle ...
- 纯css实现不固定行数的文本在一个容器内垂直居中
项目中要实现的效果如图: html代码 及 css代码: <!DOCTYPE html> <html> <head> <meta charset=" ...
- 初始化css文件
首先我们需要了解一下为什么需要公共样式(公共样式是为了初始化某些标签的默认值): 1. 因为浏览器的兼容问题,不同浏览器对有些标签的默认值是不同的,如果没对CSS初始化往往会出现浏览器之间的页面显示差 ...
- 【BZOJ3456】轩辕朗的城市规划 EGF+多项式求ln
我们构造$f(i)$和$g(i)$. 其中$f(x)$表示由$x$个节点构成的无向简单连通图的个数. $g(x)$表示有$x$个节点构成的无向简单图(不要求连通)的个数. 显然,由$x$个节点构成的无 ...
- Jasmine入门(下)
上一篇 Jasmine入门(上) 介绍了Jasmine以及一些基本的用法,本篇我们继续研究Jasmine的其他一些特性及其用法(注:本篇中的例子均来自于官方文档). Spy Spy用来追踪函数的调用历 ...
- Class与Style绑定
本文主要介绍如何使用Vue来绑定操作元素的class列表和内联样式(style属性). 因为class和style都是属性,所以通过v-bind命令来处理它们:只需要通过表达式计算出结果即可,不过字符 ...
- Tomcat性能调优-让小猫飞奔
一.总结前一天的学习 从“第三天”的性能测试一节中,我们得知了决定性能测试的几个重要指标,它们是: ü 吞吐量 ü Responsetime ü Cpuload ü MemoryUsa ...
- 使用 Chrome 生成 UUID
打开Chrome,键入 Ctrl + Shift + J,打开 JS 控制台,然后输入下面的JS代码: function getGUID( ) { function _p8(s) { var p = ...
- springboot-15-启动时加载数据的方法CommandLineRunner
有时需要爱项目启动时, 去加载一些配置文件什么的, 可以使用监听器的方式加载, 这是可以通过实现接口 CommandLineRunner来实现需求: Spring Boot应用程序在启动后,会遍历Co ...
- Golang 并发Groutine实例解读(二)
go提供了sync包和channel机制来解决协程间的同步与通信. 一.sync.WaitGroup sync包中的WaitGroup实现了一个类似任务队列的结构,你可以向队列中加入任务,任务完成后就 ...