Description
给出两个只由小写字母组成的字符串S,TS,T以及一个小写字母的排列,这两个字符串是以这个排列为密钥加密后的密文,依旧记两个字符串的原文为S,TS,T,对TT的一个长度为的子串,只要这两个字符串每个位置的字母差值不超过11则视为两个字符串匹配,问有多少子串与SS匹配,输出这些子串在中的起始位置
Input
输入两个只由小写字母组成的字符串S,TS,T,之后输入一个小写字母的排列
(1≤|S|≤|T|≤250000)(1≤|S|≤|T|≤250000)
Output
输出TT与匹配的子串数量以及这些子串在TT中的起始位置
Sample Input
any
amyisaboy
abcdefghijklmnopqrstuvwxyz
Sample Output
2
1 7
Solution
首先将和TT解密,假设串长分别为n,mn,m,那么问题转化为求TT的一个长度为的子串使得该子串与SS的对应位置差值绝对值不超过,假设该子串为Ti,...,Ti+n−1Ti,...,Ti+n−1,那么只要∑j=0n−1(Sj−Ti+j)2((Sj−Ti+j)2−1)=0∑j=0n−1(Sj−Ti+j)2((Sj−Ti+j)2−1)=0则该子串合法,将该多项式拆开转化为
∑j=0n−1(S4j+T4i+j−S2j−T2i+j−4S3jTi+j−4SjT3i+j+6S2jT2i+j−2SjTi+j)=0,0≤i≤m−n∑j=0n−1(Sj4+Ti+j4−Sj2−Ti+j2−4Sj3Ti+j−4SjTi+j3+6Sj2Ti+j2−2SjTi+j)=0,0≤i≤m−n
假设T~T~为TT的反串,那么,其中S⊙T~S⊙T~表示SS和的卷积
故只要用FFTFFT做四遍卷积得到上述表达式的值统计00的个数即为答案,时间复杂度
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
#define y1 yyy1
typedef long long ll;
#define maxn 250005
#define maxfft 524288+5
const double pi=acos(-1.0);
struct cp
{
double a,b;
cp operator +(const cp &o)const {return (cp){a+o.a,b+o.b};}
cp operator -(const cp &o)const {return (cp){a-o.a,b-o.b};}
cp operator *(const cp &o)const {return (cp){a*o.a-b*o.b,b*o.a+a*o.b};}
cp operator *(const double &o)const {return (cp){a*o,b*o};}
cp operator !() const{return (cp){a,-b};}
}w[maxfft];
int pos[maxfft];
void fft_init(int len)
{
int j=0;
while((1<<j)<len)j++;
j--;
for(int i=0;i<len;i++)
pos[i]=pos[i>>1]>>1|((i&1)<<j);
}
void fft(cp *x,int len,int sta)
{
for(int i=0;i<len;i++)
if(i<pos[i])swap(x[i],x[pos[i]]);
w[0]=(cp){1,0};
for(unsigned i=2;i<=len;i<<=1)
{
cp g=(cp){cos(2*pi/i),sin(2*pi/i)*sta};
for(int j=i>>1;j>=0;j-=2)w[j]=w[j>>1];
for(int j=1;j<i>>1;j+=2)w[j]=w[j-1]*g;
for(int j=0;j<len;j+=i)
{
cp *a=x+j,*b=a+(i>>1);
for(int l=0;l<i>>1;l++)
{
cp o=b[l]*w[l];
b[l]=a[l]-o;
a[l]=a[l]+o;
}
}
}
if(sta==-1)for(int i=0;i<len;i++)x[i].a/=len,x[i].b/=len;
}
cp x[maxfft],y[maxfft],z[maxfft];
void FFT(int *a,int *b,int n,int m,ll *c)
{
int len=1;
while(len<(n+m+1)>>1)len<<=1;
fft_init(len);
for(int i=n/2;i<len;i++)x[i].a=x[i].b=0;
for(int i=m/2;i<len;i++)y[i].a=y[i].b=0;
for(int i=0;i<n;i++)(i&1?x[i>>1].b:x[i>>1].a)=a[i];
for(int i=0;i<m;i++)(i&1?y[i>>1].b:y[i>>1].a)=b[i];
fft(x,len,1),fft(y,len,1);
for(int i=0;i<len/2;i++)
{
int j=len-1&len-i;
z[i]=x[i]*y[i]-(x[i]-!x[j])*(y[i]-!y[j])*(w[i]+(cp){1,0})*0.25;
}
for(int i=len/2;i<len;i++)
{
int j=len-1&len-i;
z[i]=x[i]*y[i]-(x[i]-!x[j])*(y[i]-!y[j])*((cp){1,0}-w[i^len>>1])*0.25;
}
fft(z,len,-1);
for(int i=0;i<n+m;i++)
if(i&1)c[i]=(ll)(z[i>>1].b+0.5);
else c[i]=(ll)(z[i>>1].a+0.5);
}
char S[maxn],T[maxn],P[30];
int x1[maxn],x2[maxn],x3[maxn];
int y1[maxn],y2[maxn],y3[maxn];
ll X2,X4,s2[maxn],s4[maxn],temp[2*maxn],ans[maxn];
int main()
{
scanf("%s%s%s",S,T,P);
int n=strlen(S),m=strlen(T);
X2=X4=0;
for(int i=0;i<n;i++)
{
x1[i]=P[S[i]-'a']-'a';
x2[i]=x1[i]*x1[i];
x3[i]=x1[i]*x2[i];
X2+=x2[i],X4+=x2[i]*x2[i];
}
for(int i=0;i<m;i++)
{
y1[i]=P[T[i]-'a']-'a';
y2[i]=y1[i]*y1[i];
y3[i]=y1[i]*y2[i];
s2[i]=i?s2[i-1]+y2[i]:y2[i];
s4[i]=i?s4[i-1]+y2[i]*y2[i]:y2[i]*y2[i];
}
for(int i=0;i<=m-n;i++)
{
ans[i]=X4-X2;
ans[i]+=(s4[i+n-1]-(i?s4[i-1]:0));
ans[i]-=(s2[i+n-1]-(i?s2[i-1]:0));
}
reverse(y1,y1+m),reverse(y2,y2+m),reverse(y3,y3+m);
FFT(x3,y1,m,m,temp);
for(int i=0;i<=m-n;i++)ans[i]-=4ll*temp[m-1-i];
FFT(x1,y3,m,m,temp);
for(int i=0;i<=m-n;i++)ans[i]-=4ll*temp[m-1-i];
FFT(x2,y2,m,m,temp);
for(int i=0;i<=m-n;i++)ans[i]+=6ll*temp[m-1-i];
FFT(x1,y1,m,m,temp);
for(int i=0;i<=m-n;i++)ans[i]+=2ll*temp[m-1-i];
vector<int>v;
for(int i=0;i<=m-n;i++)
if(!ans[i])v.push_back(i+1);
printf("%d\n",v.size());
for(int i=0;i<v.size();i++)
printf("%d%c",v[i],i==v.size()-1?'\n':' ');
return 0;
}