zoukankan      html  css  js  c++  java
  • 【JZOJ5093】【GDSOI2017第四轮模拟day3】字符串匹配 哈希

    题面

    对于一个字符集大小为C的字符串P,我们可以将任意两种字符在P中的位置进行互换,例如P=abcba,我们交换a,b就变为bacab,交换a,d就变为dbcbd,交换可以进行任意次。若交换后P变为了字符串Q,则我们称Q与P是匹配的。
    现在给定两个字符集大小为C的字符串S,T,请你求出S中有多少个连续子串与T是匹配的。
    100%的数据:1 <= n,m,C <= 10^6 , Case = 3

    100

    考虑哈希,
    我们给一个长度为m的序列,规定它的哈希值为:(sum_{c elong C}hh^{fi_c}*sum_{T_i=c}HH^{i-fi_c})
    那么维护这个哈希值就好了。

    Code

    #include<iostream>
    #include<algorithm>
    #include<math.h>
    #include<stdio.h>
    #include<string.h>
    #define ll long long
    #define fo(i,x,y) for(int i=x;i<=y;i++)
    #define fd(i,x,y) for(int i=x;i>=y;i--)
    using namespace std;
    const int inf=0x7fffffff;
    const char* fin="string.in";
    const char* fout="string.out";
    const int maxn=1000007;
    const ll mo=1000000007ll;
    int t,C,n,m,ans,a[maxn],fi[maxn],en[maxn],ne[maxn];
    int dans[maxn];
    ll h,H,hh[maxn],HH[maxn],nh[maxn],nH[maxn],_h[maxn],_H[maxn],_fi[maxn];
    int read(){
    	int x=0;
    	char ch=getchar();
    	while (ch<'0' || ch>'9') ch=getchar();
    	while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	return x;
    }
    ll qpower(ll a,ll b){
    	ll c=1;
    	while (b){
    		if (b&1) c=c*a%mo;
    		a=a*a%mo;
    		b>>=1;
    	}
    	return c;
    }
    ll ni(ll v){return qpower(v,mo-2);}
    void update(int de,int now){
    	if (_fi[de]<now){
    		int tmp=now-_fi[de];
    		_h[de]=_h[de]*nh[tmp]%mo;
    		_H[de]=_H[de]*nh[tmp]%mo;
    		_fi[de]=now;
    	}
    }
    int main(){
    	freopen(fin,"r",stdin);
    	freopen(fout,"w",stdout);
    	scanf("%d%d",&t,&C);
    	hh[0]=HH[0]=nh[0]=nH[0]=1;
    	ll hhh=ni(797ll),HHH=ni(648567ll);
    	fo(i,1,maxn-1){
    		hh[i]=797ll*hh[i-1]%mo,HH[i]=648567ll*HH[i-1]%mo;
    		nh[i]=hhh*nh[i-1]%mo,nH[i]=HHH*nH[i-1]%mo;
    	}
    	while (t--){
    		scanf("%d%d",&n,&m);
    		fo(i,1,n) a[i]=read();
    		h=H=0;
    		memset(fi,0,sizeof fi);
    		fo(i,1,m){
    			int j=read();
    			if (!fi[j]) H=(H+hh[fi[j]=i])%mo;
    			else H=(H+hh[fi[j]]*HH[i-fi[j]])%mo;
    		}
    		memset(fi,0,sizeof fi);
    		memset(ne,0,sizeof ne);
    		//memset(_h,0,sizeof _h);
    		fo(i,1,m){
    			int j=a[i];
    			if (!fi[j]){
    				h=(h+hh[fi[j]=en[j]=i])%mo;
    				_h[j]=_H[j]=hh[i];
    				_fi[j]=1;
    			}else{
    				ne[en[j]]=i;
    				en[j]=i;
    				h=(h+hh[fi[j]]*HH[i-fi[j]])%mo;
    				_h[j]=(_h[j]+hh[fi[j]]*HH[i-fi[j]])%mo;
    			}
    		}
    		dans[0]=0;
    		ans=(H==h);
    		if (H==h) dans[++dans[0]]=1;
    		fo(i,m+1,n){
    			int ad=a[i],de=a[i-m];
    			h=(h*nh[1])%mo;
    			//_h[de],_H[de]
    			update(de,i-m+1);
    			//
    			h-=_h[de];
    			if (ne[fi[de]]){
    				int tmp=ne[fi[de]]-fi[de];
    				fi[de]=ne[fi[de]];
    				_h[de]-=_H[de];
    				_H[de]=_H[de]*hh[tmp]%mo;
    				_h[de]=_h[de]*hh[tmp]%mo*nH[tmp]%mo;
    			}else fi[de]=0,_h[de]=0;
    			h+=_h[de];
    			//
    			if (!fi[ad]){
    				fi[ad]=en[ad]=i;
    				h=(h+hh[m])%mo;
    				_h[ad]=_H[ad]=hh[m];
    				_fi[ad]=i-m+1;
    			}else{
    				ne[en[ad]]=i;
    				en[ad]=i;
    				update(ad,i-m+1);
    				h=(h+_H[ad]*HH[i-fi[ad]])%mo;
    				_h[ad]=(_h[ad]+_H[ad]*HH[i-fi[ad]])%mo;
    			}
    			h=(h%mo+mo)%mo;
    			ans+=(H==h);
    			if (H==h) dans[++dans[0]]=i-m+1;
    		}
    		printf("%d
    ",ans);
    		fo(i,1,dans[0]) printf("%d ",dans[i]);
    		printf("
    ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    类模板机制
    C和C++中const的区别
    bitset
    静态库or动态库?
    多态原理探究
    程序从编译到运行过程
    对象的内存模型
    重载、重写(覆盖)和隐藏
    对继承和派生的理解
    对C++对象的理解
  • 原文地址:https://www.cnblogs.com/hiweibolu/p/6774702.html
Copyright © 2011-2022 走看看