【题解】Rusty String [CF827E]

传送门:\(\text{Rusty String}\) \(\text{[CF827E]}\)

【题目描述】

多组数据,每组数据给出一个由 \(V,K,?\) 三种字符组成的字符串,其中 \(?\) 可以替换为 \(V,K\) 中的任意一个,求替换后的字符串可以存在的循环周期有哪些。

【分析】

乍一看像是带通配符的字符串匹配(不会的强烈建议去康康这个),由于字符集不大,按照套路就应该枚举两个字符 \(a \ne b\in\{V,K\}\),然后设 \(f(i)=[A[i]=a],\) \(g(i)=[A[i]=b]\)

则有: \(PA(k)=\sum_{i=1}^{n}f(i)g(i+k)\),翻转 \(f\) 得到:\(PA(k)=\sum_{i=1}^{n}f(n-i+1)g(i+k)\) \(=\sum_{i+j=n+k+1}f(i)g(j)\)

很明显是个 \(\text{FFT}\) 的板子,把式子卷起来就可以了。

按照以往的“经验”,或者说惯性思维,多半会这样做(比如说我),但写出来却发现酱紫连第一个样例都过不了。

那么问题出在哪儿了呢?

注意:当 \(PA(k) \ne 0\) 时说明在某个地方出现了 \('V'\) 与 \('K'\) 相对应的情况,以 \(k\) 作为周期肯定不合法,但 \(PA(k) = 0\) 并不能说明 \(k\) 一定是合法周期,因为这道题中的特殊符号不是通配符,而是未知字符,通配符可以任意匹配,但未知字符只能匹配一种。

比如样例 \(1\),用上面的错误算法多输出了一个 \(2\),在这种情况下 \(S_3('?')\) 分别与 \(S_1('V'),S_5('K')\) 进行了匹配,因此以 \(2\) 作为周期是不合法的。

考虑改进算法:

之前的做法错在算出来的式子只进行了一周目的匹配判断,那么我们只要将二周目、三周目……全部都判断一下就好了呀,正巧序列 \(PA\) 完美的包含了所有长度的循环情况,所以直接暴力枚举周期的倍数即可(复杂度为 \(O(\frac{n}{1}+\frac{n}{2}+\frac{n}{3} \cdots \frac{n}{n})=O(nlogn)\))。

总时间复杂度为:\(O(nlogn)\) 。

你说啥?卡常?玄学优化减少调用次数?不存在的,我写了这么久的 \(\text{NTT}\),还从未被卡过(小骄傲)。

\(\text{emm...}\)

等等,还没完,仔细看题啊:“保证输入字符串总长不超过 \(5∗10^5\) 。” 注意是输入总长,所以不要偷懒用 \(\text{memset}\)!

【Code】

#include<algorithm>
#include<cstring>
#include<cstdio>
#define LL long long
#define Re register int
using namespace std;
const int N=1048576+3,P=998244353,G=3;
int n,T,ans,invG,f[N],g[N],tr[N],PA[N],can[N];char A[N];
inline void in(Re &x){
int f=0;x=0;char c=getchar();
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=f?-x:x;
}
inline int mi(Re x,Re k){
Re s=1;
while(k){
if(k&1)s=(LL)s*x%P;
x=(LL)x*x%P,k>>=1;
}
return s;
}
inline int inv(Re x){return mi(x,P-2);}
inline void NTT(Re *f,Re n,Re op){
for(Re i=0;i<n;++i)if(i<tr[i])swap(f[i],f[tr[i]]);
for(Re p=2;p<=n;p<<=1){
Re len=p>>1,w1=mi(op?invG:G,(P-1)/p);
for(Re st=0;st<n;st+=p)
for(Re j=st,base=1;j<=st+len-1;++j){
Re tmp=(LL)base*f[j+len]%P;
f[j+len]=(f[j]-tmp+P)%P,(f[j]+=tmp)%=P;
base=(LL)base*w1%P;
}
}
}
inline void sakura(Re *f,Re n,Re *g,Re m){//卷卷卷
Re n_=n;
for(m+=n,n=1;n<=m;n<<=1);Re invn=inv(n);
for(Re i=n_+1;i<=n;++i)f[i]=g[i]=0;//注意初始化
for(Re i=1;i<n;++i)tr[i]=(tr[i>>1]>>1)|((i&1)?n>>1:0);
NTT(f,n,0),NTT(g,n,0);
for(Re i=0;i<n;++i)f[i]=(LL)f[i]*g[i]%P;
NTT(f,n,1);
for(Re i=0;i<=m;++i)f[i]=(LL)f[i]*invn%P;
}
int main(){
// freopen("123.txt","r",stdin);
in(T),invG=inv(G);
while(T--){
in(n),scanf("%s",A+1),ans=0;
for(Re i=1;i<=n;++i)PA[i]=0;//注意初始化
for(Re i=1;i<=n;++i)f[n-i+1]=(A[i]=='K'),g[i]=(A[i]=='V');
sakura(f,n,g,n);
for(Re i=1;i<n;++i)PA[i]+=f[i+n+1];//PA[n]可以不用管,因为一定合法
for(Re i=1;i<=n;++i)f[n-i+1]=(A[i]=='V'),g[i]=(A[i]=='K');
sakura(f,n,g,n);
for(Re i=1;i<n;++i)PA[i]+=f[i+n+1];
for(Re i=1;i<=n;++i){
can[i]=1;
for(Re j=i;j<=n&&can[i];j+=i)can[i]&=(!PA[j]);//枚举倍数依次判断
ans+=can[i];
}
printf("%d\n",ans);
for(Re i=1;i<=n;++i)if(can[i])printf("%d ",i);puts("");
}
}

【题解】Rusty String [CF827E]的更多相关文章

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

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

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

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

  3. E. Rusty String

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

  4. PAT甲题题解-1050. String Subtraction (20)-水题

    #include <iostream> #include <cstdio> #include <string.h> #include <algorithm&g ...

  5. CF 827E Rusty String FFT

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

  6. 《LeetBook》leetcode题解(8): String to Integer (atoi) [E]——正负号处理

    我现在在做一个叫<leetbook>的免费开源书项目,力求提供最易懂的中文思路,目前把解题思路都同步更新到gitbook上了,需要的同学可以去看看 书的地址:https://hk029.g ...

  7. LeetCode题解 #8 String to Integer (atoi)

    又是一道恶心的简单题. 一开始没想到这么多情况的,幸好LeetCode是个很人性化的oj,能让你知道你在哪个case上错了,否则一辈子都过不了. 考虑不周到只能一个个补了. 列举一下恶心的case / ...

  8. leetcode个人题解——#8 string to integer

    第八题 class Solution { public: int myAtoi(string str) { ; ; ; while(str[i] == ' ')i++; if (str[i] == ' ...

  9. 题解-Codeforces710F String Set Queries

    咕了好久没更博客,最近得知可以去冬眠营玩耍,还可以搭顺风车回广州过年 (最近做到的比较有意思的题目:bzoj3958.hihocoder1419) Problem Codeforces-710F--洛 ...

随机推荐

  1. 题解【洛谷P3574】[POI2014]FAR-FarmCraft

    题面 简化版题意: 有一棵 \(n\) 个点的树,有边权. 你初始在 \(1\) 号节点,你需要走遍整棵树为 \(2 \sim n\) 号点的居民分发电脑,但你的汽油只够经过每条边恰好两次. 一个居民 ...

  2. 题解 【Codefoeces687B】Remainders Game

    题意: 给出c1,c2,...cn,问对于任何一个正整数x,给出x%c1,x%c2,...的值x%k的值是否确定; 思路: 中国剩余定理.详见https://blog.csdn.net/acdream ...

  3. Python之旅的开始day1

    Python有哪些种类: JPython.IronPython.JavaScriptPython.RubyPython.CPython(即将开始学习种类,最为常见的种类).pypy pypy:这是用C ...

  4. 题解 【Codeforces381A】 Sereja and Dima

    本题是很好的双指针练习题. 关于双指针,详见洛谷日报#73. 我们可以用两个指针l和r表示题中两人接下来要比较的数字,用fl标记下一个将要取的人,并分别用两个计数器统计双方的答案. 因此,我们有了如下 ...

  5. golang中的net/rpc包

    本文先介绍RPC,然后go原生对RPC的使用,之后是介绍go语言中有哪些RPC框架以及一些其他常见的框架,最后是探究go语言中rpc的源码. (1)首先介绍下什么RPC? (2)RPC可以做什么? ( ...

  6. [人物存档]【AI少女】【捏脸数据】人物鉴赏190

    AISChaF_20200201011129905.png AISChaF_20200123004135233.png

  7. winform学习(1)初识winform

    winform是Windows窗体应用程序 在窗体设计界面  单击鼠标右键--查看代码,即可转到Form1.cs的代码界面 从代码界面转到窗体设计界面的三种快捷方法:①双击解决方案资源管理器的 For ...

  8. pudn免费下载账号 codeforge积分账号 pudn共享账号 codeforge下载账号

    www.pudn.com和www.codeforge.cn网站下载代码很好,没有积分怎么办?那么多好的matlab代码,matlab程序,C,JAVA等等,都要充值啊!!! 下面的账号积分都用完了,大 ...

  9. spring 配置

    在context中配置 如:在base-package指明一个包: <context:component-scan base-package="cn.edu.dao"/> ...

  10. 13.56Mhz下直接阻抗匹配调试步骤

    直接匹配阻抗,天线与射频芯片在同一块板子,调试步骤与50欧姆阻抗匹配调试天线参数差不多,多了一部分射频芯片端的滤波部分的参数计算.下面介绍调试过程. 1.首先看一下射频芯片发射部分原理图:分析原理图时 ...