Description
给出两个只由小写字母组成的字符串 S,T S , T 以及一个小写字母的排列,这两个字符串是以这个排列为密钥加密后的密文,依旧记两个字符串的原文为 S,T S , T ,对 T T 的一个长度为的子串,只要这两个字符串每个位置的字母差值不超过 1 1 则视为两个字符串匹配,问有多少子串与 S S 匹配,输出这些子串在中的起始位置
Input
输入两个只由小写字母组成的字符串 S,T S , T ,之后输入一个小写字母的排列
(1≤|S|≤|T|≤250000) ( 1 ≤ | S | ≤ | T | ≤ 250000 )
Output
输出 T T 与匹配的子串数量以及这些子串在 T T 中的起始位置
Sample Input
any
amyisaboy
abcdefghijklmnopqrstuvwxyz
Sample Output
2
1 7
Solution
首先将和 T T 解密,假设串长分别为 n,m n , m ,那么问题转化为求 T T 的一个长度为的子串使得该子串与 S S 的对应位置差值绝对值不超过,假设该子串为 Ti,...,Ti+n−1 T i , . . . , T i + n − 1 ,那么只要 ∑j=0n−1(Sj−Ti+j)2((Sj−Ti+j)2−1)=0 ∑ j = 0 n − 1 ( S j − T i + j ) 2 ( ( S j − T i + 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 = 0 n − 1 ( S j 4 + T i + j 4 − S j 2 − T i + j 2 − 4 S j 3 T i + j − 4 S j T i + j 3 + 6 S j 2 T i + j 2 − 2 S j T i + j ) = 0 , 0 ≤ i ≤ m − n
假设 T~ T ~ 为 T T 的反串,那么,其中 S⊙T~ S ⊙ T ~ 表示 S S 和的卷积
故只要用 FFT F F T 做四遍卷积得到上述表达式的值统计 0 0 的个数即为答案,时间复杂度
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;
}