zoukankan      html  css  js  c++  java
  • CF1334G Substring Search

    题目传送门

    分析:
    我们先看看如果不需要置换,我们如何将(S)匹配进(T)
    (废话当然是kmp或者hash了
    能否用函数求解呢?
    两个字符(S_i,T_j)相同,当且仅当((S_i-T_j)^2=0)
    于是对于串(T),以结束位置为自变量做一个函数(P(x)),把(S)串反转

    (P(x)=sum_{i=1}^{m}(S_i-T_{x+i-m})^2)

    (P(x)=0)时,说明这个位置结束的串可以匹配
    式子展开,中间的(S_{i}T_{j})用NTT求一下就好了

    接下来考虑置换,同理
    两个字符(S_i,T_j)相同,当且仅当((S_i-T_j)^2(P_{S_i}-T_j)^2=0)
    同样适用NTT求解(但是要做7次)
    我反正没卡过时限,考虑奇奇怪怪的技巧
    我们尝试把平方抹去,(P(x))变成

    (P(x)=sum_{i=1}^{m}(S_i-T_{x+i-m})(P_{S_i}-T_{x+i-m}))

    这个明显是错误的,在(S)(T)值域只有([1,26])时随随便便就挂了
    那就把值域变一下,把每个字符的值在NTT模数取模下随机
    这样正确率就很高了
    (还可能被卡?换个NTT模数,998244353众人皆知,1004535809就很棒
    我用的998244353,到时候视情况而定吧(也可以随机两次或者三次来做
    反正就是乱搞(

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    
    #define maxn 800005
    #define INF 0x3f3f3f3f
    #define MOD 998244353
    
    using namespace std;
    
    inline long long getint()
    {
    	long long num=0,flag=1;char c;
    	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    	return num*flag;
    }
    
    int n,m;
    int A[maxn],B[maxn],F[maxn],G[maxn],H[maxn],p[maxn],P[maxn];
    int pre[maxn],rev[maxn],w[maxn];
    char S[maxn],T[maxn];
    int ans,sum;
    
    inline int upd(int x){return x<MOD?x:x-MOD;}
    inline int ksm(int num,int k)
    {
    	int ret=1;
    	for(;k;k>>=1,num=1ll*num*num%MOD)if(k&1)ret=1ll*ret*num%MOD;
    	return ret;
    }
    
    inline void NTT(int *a,int len,int op)
    {
    	for(int i=0;i<len;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
    	for(int i=1;i<len;i<<=1)for(int j=0,wn=ksm(op==1?3:332748118,(MOD-1)/(i<<1));j<len;j+=(i<<1))
    		for(int k=0,w=1;k<i;k++,w=1ll*w*wn%MOD)
    		{
    			int x=a[j+k],y=1ll*a[i+j+k]*w%MOD;
    			a[j+k]=upd(x+y),a[i+j+k]=upd(x-y+MOD);
    		}
    	if(!~op)for(int i=0,Inv=ksm(len,MOD-2);i<len;i++)a[i]=1ll*a[i]*Inv%MOD;
    }
    
    inline void mul(int *a,int *b)
    {
    	int len=1;
    	while(len<(n+m))len<<=1;
    	for(int i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|(i&1?len>>1:0);
    	NTT(a,len,1),NTT(b,len,1);
    	for(int i=0;i<len;i++)a[i]=1ll*a[i]*b[i]%MOD;
    	NTT(a,len,-1);
    }
    
    int main()
    {
    	for(int i=1;i<=26;i++)p[i]=getint();
    	scanf("%s%s",S,T);
    	n=strlen(T),m=strlen(S);
    	for(int i=0;i<m-i-1;i++)swap(S[i],S[m-i-1]);
    	for(int i=1;i<=26;i++)w[i]=ksm(p[i],INF);
    	for(int i=0;i<n;i++)
    	{
    		F[i]=w[T[i]-96];
    		pre[i]=upd((i?pre[i-1]:0)+1ll*F[i]*F[i]%MOD);
    	}
    	for(int i=0;i<m;i++)
    	{
    		G[i]=w[S[i]-96];
    		H[i]=w[p[S[i]-96]];
    		sum=upd(sum+1ll*G[i]*H[i]%MOD);
    	}
    	for(int i=0;i<n;i++)A[i]=F[i];
    	for(int i=0;i<m;i++)B[i]=upd(G[i]+H[i]);
    	mul(A,B);
    	for(int i=0;i<n+m;i++)P[i]=upd(MOD-A[i]);
    	for(int i=m-1;i<n;i++)
    	{
    		P[i]=upd(P[i]+upd(pre[i]-(i>=m?pre[i-m]:0)+MOD));
    		P[i]=upd(P[i]+sum);
    		printf("%d",!P[i]);
    	}
    	printf("
    ");
    }
    

  • 相关阅读:
    【CF833E】Caramel Clouds
    【LG2183】[国家集训队]礼物
    (ex)Lucas总结
    【CF527C】Glass Carving
    【CF833D】Red-Black Cobweb
    【LG4631】[APIO2018]Circle selection 选圆圈
    volatile梳理
    ThreadLocal梳理
    java线程基础梳理
    TCP/IP
  • 原文地址:https://www.cnblogs.com/Darknesses/p/12975783.html
Copyright © 2011-2022 走看看