UVALive 4671 K-neighbor substrings 巧用FFT

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;
}

  

原文地址:https://www.cnblogs.com/heisenberg-/p/6561990.html