• SD2018集训Day2 子串


    SD2018集训Day2 子串

    给定一个长度为 (m) 的串 (S),其中每个求有多少长度为 (n) 的子串 (t),满足对其作用一次排列 (p) 之后 不变,即 (t_i = t_{p_i})(S) 的字符集大小是 (c),每个字符都是一个 (1)(c) 中的数字。(n,m,cleq 5e5)

    这题是个NTT算hash,先算出每个长度为 (n) 的子串的hash值,直接把base的幂数组倒过来和字符串卷即可。(差一定倒过来卷)

    然后按排列的顺序把幂数组循环移位,再卷一下判断和原来每个串hash是否相等。

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 2e6+200; 
    int n,m,c;
    int p[N],S[N],f[N];
    int p1[N],p2[N]; 
    const int mod = 998244353;
    const int bas = 1145141;
    int lim,l,r[N*4];
    int omg[N][2];
    #define FOR(i,a,b) for(int i=a;i<=b;++i)
    int ksm(int a,int b){
    	int res=1;
    	while(b){
    		if(b&1) res=1ll*res*a%mod;
    		a=1ll*a*a%mod;b>>=1;
    	}
    	return res;
    }
    void init(){
    	omg[0][1]=1;omg[0][0]=1;
    	omg[1][1]=ksm(3,(mod-1)/lim);
    	omg[1][0]=ksm(omg[1][1],mod-2);
    	FOR(i,2,lim-1){
    		omg[i][0]=1ll*omg[i-1][0]*omg[1][0]%mod;
    		omg[i][1]=1ll*omg[i-1][1]*omg[1][1]%mod;
    	}
    	FOR(i,1,lim-1){
    		r[i]=(r[i>>1]>>1)|((i&1)?(1<<(l-1)):0);
    	}
    }
    void ntt(int *a,int opt){
    	FOR(i,0,lim-1) if(i<r[i]) swap(a[i],a[r[i]]); 
    	for(register int l=2;l<=lim;l<<=1){
    		int m=l/2;
    		for(int *g=a;g!=a+lim;g+=l){
    			for(register int i=0;i<m;++i){
    				int t=1ll*g[i+m]*omg[lim/l*i][opt]%mod;
    				g[i+m]=(g[i]-t+mod)%mod;
    				g[i]=(g[i]+t)%mod;
    			}
    		}
    	}
    	if(!opt){
    		int iv=ksm(lim,mod-2);
    		FOR(i,0,lim) a[i]=1ll*a[i]*iv%mod;
    	}
    }
    int main(){
    	freopen("sub.in", "r", stdin);
        freopen("sub.out", "w", stdout);
    	scanf("%d %d %d",&n,&m,&c);
    	FOR(i,0,n-1){
    		scanf("%d",&p[i]);p[i]--;
    	}
    	FOR(i,0,m-1){
    		scanf("%d",&S[i]);
    	}
    	f[0]=1;FOR(i,1,n-1) f[i]=1ll*f[i-1]*bas%mod; 
    	FOR(i,0,n-1) p1[n-1-i]=f[i];
    	FOR(i,0,n-1) p2[n-1-p[i]]=f[i];
    	lim=1,l=0;while(lim<2*m) lim<<=1,l++;
    	init();
    	ntt(p1,1);ntt(p2,1);ntt(S,1);
    	FOR(i,1,lim) p1[i]=(1ll*p1[i]*S[i])%mod,p2[i]=(1ll*p2[i]*S[i])%mod;
    	ntt(p1,0);ntt(p2,0);
    	FOR(i,0,m-n){
    		if(p1[i+n-1]==p2[i+n-1]){
    			printf("1");
    		}else printf("0");
    	}
    	return 0;
    }
    
  • 相关阅读:
    Android 绑定Service的实现方法二:使用Messenger
    Android 利用SurfaceView进行图形绘制
    Android 垂直SeekBar
    Android Camera(一) 调用系统相机应用
    Android Camera(二) Camera程序编写
    算法题009 电梯调度算法
    Git基础使用教程:第一个Git项目
    Android上的GPS程序报错:Fail to find provider info for com.google.android.gsf.gservices
    JUnit4:多组数据的单元测试:用JUnit4做参数化测试
    Git基础:添加与提交
  • 原文地址:https://www.cnblogs.com/lcyfrog/p/14263947.html
Copyright © 2020-2023  润新知