2009 hefei K-neighbor substrings(FFT)

http://acm.ustc.edu.cn/ustcoj/source.php?id=82828

数据是水过去了,但是bug还在(找不出啊);

 

我把mod改为19998过了,运气啊,可是改成其他东西就过不了,还有uvalive上一直T,哎~,伤不起啊。

 

最重要的思想:

假如把a[0,m],b[0,m],看成两个多项式,a看作 1,b看作0,那么先把b[0,m]转置,那么有多少个a相同的位是不是等价于多项式系数为m前的系数呢!同理把a看作0,b看作1。

然后就可以在nlogn的时间内得到系数。

最后hash一下字符串就能得到结果。

hash的方法:离散化,map,邻接表

 

#include <stdio.h>
#include <deque>
#include <set>
#include <string>
#include <map>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
typedef long long LL;
const double Pi = acos(-1.0);
const int maxn = 200005;
map<string,int> mymap;

char a[maxn],b[maxn],c[maxn];

struct complex{
	double r,i;
	complex(double _r=0, double _i=0){
		r = _r;
		i = _i;
	}

	complex operator +(const complex &b){
		return complex(r+b.r,i+b.i);
	}

	complex operator -(const complex &b){
		return complex(r-b.r,i-b.i);
	}

	complex operator *(const complex &b){
		return complex(r*b.r-i*b.i,r*b.i+i*b.r);
	}

}x[maxn*2],y[maxn*2];

void brc(complex y[],int len){
	int i,j,k;
	for(i=1,j=len/2;i<len-1;i++){
		if(i < j)swap(y[i],y[j]);
		k = len / 2;
		while(j >= k){
			j -= k;
			k /= 2;
		}
		if(j < k)j += k;
	}
}

void FFT(complex y[],int len,int on){
	brc(y,len);
	for(int h=2;h<=len;h<<=1){
		complex wn(cos(-on*2*Pi/h),sin(-on*2*Pi/h));
		for(int j=0;j<len;j+=h){
			complex w(1.0);
			for(int k=j;k<j+h/2;k++){
				complex u = y[k];
				complex t = w * y[k+h/2];
				y[k] = u + t;
				y[k+h/2] = u - t;
				w = w * wn;
			}
		}
	}
	if(on == -1){
		for(int i=0;i<len;i++){
			y[i].r /= len;
		}
	}
}

int len;
int strlena;
int strlenb;


void mul(int c[],char cmp){
	//printf("l:%d\n",strlena);
	len = 1;
	while(len < strlena)len *= 2;
	len *= 2;
	for(int i=0;i<strlena;i++){
		if(a[i] == cmp){
			x[i] = complex(1,0);
		}
		else {
			x[i] = complex(0,0);
		}
	}
	for(int i=strlena;i<len;i++){
		x[i] = complex();
	}

	for(int i=0;i<strlenb;i++){
		if(b[i] == cmp){
			y[i] = complex(1,0);
		}
		else {
			y[i] = complex(0,0);
		}
	}

	for(int i=strlenb;i<len;i++){
		y[i] = complex();
	}

	FFT(x,len,1);
	FFT(y,len,1);
	for(int i=0;i<len;i++)x[i] = x[i]*y[i];
	FFT(x,len,-1);
	for(int i=0;i<strlena+strlenb;i++){
		c[i] = x[i].r + 0.5;
	}	
}

int d1[maxn];
int d2[maxn];

void printarray(int a[],int n){
	for(int i=0;i<n;i++){
		printf("%d ",a[i]);
	}
	printf("\n");
}


const int maxm = 1e5 + 7;
const int mod = 19998;
struct node{
	int v;
	int next;
}e[maxm+10];

int head[mod];
int f[maxn];
int tot;


void init(){
	memset(head,-1,sizeof(head));
	tot = 0;
}

void add(int u,int v){
	e[tot].v = v;
	e[tot].next = head[u];
	head[u] = tot++;
}

int pow2(int n){
	int ans = 1;
	int a = 2;
	while(n){
		if(n&1)ans=(ans*a)%mod;
		a = a * a % mod;
		n >>= 1;
	}
	return ans;
}

bool check1(int si,int sj){
	for(int i=0;i<strlenb;i++){
		if(a[si+i] == a[sj+i]){
			continue;
		}
		return false;
	}
	return true;
}


bool check(int u,int v){
	for(int iter=head[u];iter!=-1;iter=e[iter].next){
		if(check1(v,e[iter].v)==true){
			return true;
		}
	}
	//add(u,v);
	return false;
}




int main(){
	//string a,c,b;
	int k;
	int cas = 1;
	while(scanf("%d%s%s",&k,a,c), k != -1){
		strlena = strlen(a);
		strlenb = strlen(c);
		//printf("%d\n",k);
		//puts(a);
		//puts(c);
		for(int i=0;i<strlenb;i++){
			b[i] = c[strlenb-i-1];
		}
		b[strlenb] = '\0';
		if(strlena < strlenb){
			printf("Case %d: %d\n",cas++,0);
			continue;
		}
		mul(d1,'a');
		mul(d2,'b');
		//printarray(d1,len);
		//printarray(d2,len);
		
		//mymap.clear();
		
		/*
		for(int i=b.length()-1;i<len;i++){

		}
		*/	
		int t = 0;
		init();
		
		for(int i=0;i<strlenb;i++){
			t = (t * 2 + (a[i] - 'a'));
			if(t >= mod)t -= mod;
		}
		
		f[0] = t;
		add(f[0],0);
		int ans = 0;
		k = strlenb - k;
		if(d1[strlenb-1] + d2[strlenb-1] >= k){
			ans ++;
		}
		int p = pow2(strlenb-1);
		for(int i=strlenb,j=1;i<strlena;i++,j++){
			f[j] = (((f[j-1] - p*(a[j-1]-'a')%mod + mod)%mod)*2 + a[i]-'a');
			if(f[j]>=mod)f[j]-=mod;
			//add(f[j+1],j+1);
			if(check(f[j],j) == false){
				if(d1[i] + d2[i] >= k){
					ans ++;
				}
				add(f[j],j);
			}
		}
		printf("Case %d: %d\n",cas++,ans);
	}
	return 0;
}


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值