UVALive4671 K-neighbor substrings 给定一个两个字符串A和B B为模式串。问A中有多少不同子串与B的距离小于k 所谓距离就是不同位的个数。
由于字符串只包含a和b 我们可以换做0和1 将B反转 进行大整数乘法(卷积) 就可以轻松得出不同的位数。只有FFT能在nlogn时间内完成大整数乘法。
要求不同的子串,再进行一次字符串散列即可。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<queue>
#include<stack>
#include<complex>
//使用FFT时注意精度问题和数组大小
using namespace std;
typedef long long int LL;
const double pi=acos(-1.0);
struct Complex {
double r, i;
Complex(double _r, double _i) {
r = _r;
i = _i;
}
double real()
{
return r;
}
double ii()
{
return i;
}
Complex operator + (const Complex &c) {
return Complex(c.r + r, c.i + i);
}
Complex operator - (const Complex &c) {
return Complex(r - c.r, i - c.i);
}
Complex operator * (const Complex &c) {
return Complex(c.r * r - c.i * i, c.r * i + c.i * r);
}
Complex operator / (const int &c) {
return Complex(r / c, i / c);
}
Complex(){}
};
void build(Complex _P[],Complex P[],LL n,LL m,LL curr,LL &cnt)
{
if(n==m){_P[curr]=P[cnt++];}
else {build(_P,P,n,m*2,curr,cnt);build(_P,P,n,m*2,curr+m,cnt);}
}
const LL maxn=300000;
void FFT(Complex P[],LL n,LL oper)//返回结果向左靠齐 最后结果除n
{
static Complex _P[maxn];
LL cnt=0;
build(_P,P,n,1,0,cnt);copy(_P,_P+n,P);
for(LL d=0;(1<<d)<n;d++)
{
LL m=1<<d;
LL m2=m*2;
double p0=pi/m*oper;
Complex unit_p0=Complex(cos(p0),sin(p0));
for(LL i=0;i<n;i+=m2)
{
Complex unit=Complex(1,0);
for(LL j=0;j<m;j++)
{
Complex &P1=P[i+j+m],&P2=P[i+j];
Complex t=unit*P1;
P1=P2-t;
P2=P2+t;
unit=unit*unit_p0;
}
}
}
}
void himult(Complex p1[],Complex p2[],LL n,Complex ans[])
{
FFT(p1,n,1);FFT(p2,n,1);
for(LL i=0;i<=n;i++)
ans[i]=p1[i]*p2[i];
FFT(ans,n,-1);
}
char a[131072*2],b[131072*2];
Complex av[131072*4],bv[131072*2+1],ans1[131072*2+1];
unsigned long long int ha[200000],xp[200000];
const int seed=3;
set<unsigned long long int >vise;
bool hash(int l,int r)
{
unsigned long long int nowv= ha[r+1]-ha[l]*xp[r-l+1];
if(vise.count(nowv)==0){vise.insert(nowv);return false;}
else return true;
}
int main()
{
freopen("t.txt","r",stdin);
xp[0]=1;
for(int i=1;i<=100000;i++)
xp[i]=xp[i-1]*seed;
int ii=0;
while(1)
{ ii++;
vise.clear();
int k;
scanf("%d",&k);
if(k==-1)break;
memset(a,0,sizeof(a));memset(b,0,sizeof(b));
scanf("%s%s",&a,&b);
int la=strlen(a),lb=strlen(b);
int len=1;
while(len<=la+lb)len<<=1;
for(int i=0;i<la;i++)
av[i]=Complex(a[i]=='a'?1:-1,0);
for(int i=la;i<=len;i++)av[i]=Complex(0,0);
for(int i=0;i<lb;i++)
bv[lb-i-1]=Complex(b[i]=='a'?1:-1,0);
for(int i=lb;i<=len;i++)
bv[i]=Complex(0,0);
memset(ans1,0,sizeof(ans1));
himult(av,bv,len,ans1);
int anss=0;
ha[0]=0;
for(int i=0;i<la;i++)
ha[i+1]=ha[i]*seed+a[i];
for(int i=0;i+lb<=la;i++)
{
if(hash(i,i+lb-1))continue;
int nue=(int)(ans1[i+lb-1].r/len+0.5);
if(lb-nue<=k*2)anss++;
}
printf("Case %d: %d
",ii,anss);
}
return 0;
}