zoukankan      html  css  js  c++  java
  • 洛谷P4173 残缺的字符串

    题目大意:

    两个带通配符的字符串(a,b),求(a)(b)中出现的位置

    字符串长度(le 300000)

    考虑魔改一发(kmp),发现魔改不出来

    于是考虑上网搜题解

    然后考虑(ntt),发现两个串匹配需要满足(sumlimits_{i=0}^{n-1}(a_i-b_i)=0)

    发现不太对,可能有正有负相消等于(0),我们加上平方(sumlimits_{i=0}^{n-1}(a_i-b_i)^2=0)

    再考虑通配符,我们可以设通配符的价值为(0),然后变形一下(sumlimits_{i=0}^{n-1}a_i*b_i*(a_i-b_i)^2=0)

    展开得到(sumlimits_{i=0}^{n-1}a_i^3*b_i-2a_i^2*b_i^2+a_i*b_i^3)

    我们可以把这三项分开考虑

    对于其中一项(sumlimits_{i=0}^{n-1}a_i^3*b_i)

    (a^{'})(a)翻转,(j=n-i-1),答案为(sumlimits_{i=0}^{n-1}a_j^{'3}*b_i)

    然后卷起来,判断卷完之后(i=(m-1sim n-1))哪个系数是零,把(i-m+2)加入答案

    #include<bits/stdc++.h>
    using namespace std;
    namespace red{
    #define int long long
    	inline int read()
    	{
    		int x=0;char ch,f=1;
    		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    		if(ch=='-') f=0,ch=getchar();
    		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    		return f?x:-x;
    	}
    	const int N=3e5+10,p=998244353,g=3,gi=332748118;
    	int n,m,limit,len;
    	char a[N],b[N];
    	int pos[N<<2];
    	int ret[N],num;
    	int a1[N<<2],b1[N<<2],c[N<<2];
    	inline int fast(int x,int k)
    	{
    		int ret=1;
    		while(k)
    		{
    			if(k&1) ret=ret*x%p;
    			x=x*x%p;
    			k>>=1;
    		}
    		return ret;
    	}
    	inline void ntt(int *a,int inv)
    	{
    		for(int i=0;i<limit;++i)
    			if(i<pos[i]) swap(a[i],a[pos[i]]);
    		for(int mid=1;mid<limit;mid<<=1)
    		{
    			int Wn=fast(inv?g:gi,(p-1)/(mid<<1));
    			for(int r=mid<<1,j=0;j<limit;j+=r)
    			{
    				int w=1;
    				for(int k=0;k<mid;++k,w=w*Wn%p)
    				{
    					int x=a[j+k],y=w*a[j+k+mid]%p;
    					a[j+k]=(x+y)%p;
    					a[j+k+mid]=(x-y)%p;
    					if(a[j+k+mid]<0) a[j+k+mid]+=p;
    				}
    			}
    		}
    		if(inv) return;
    		inv=fast(limit,p-2);
    		for(int i=0;i<limit;++i) a[i]=a[i]*inv%p;
    	}
    	inline void work(int *a,int *b,int opt)
    	{
    		ntt(a,1);ntt(b,1);
    		for(int i=0;i<limit;++i) c[i]=c[i]+a[i]*b[i]*opt;
    	}
    	inline void main()
    	{
    		m=read(),n=read();
    		scanf("%s%s",a,b);
    		for(int i=0;i<m;++i)
    		{
    			if(a[i]=='*') a[i]=0;
    			else a[i]=a[i]-'a'+1;
    		}
    		for(int i=0;i<n;++i)
    		{
    			if(b[i]=='*') b[i]=0;
    			else b[i]=b[i]-'a'+1;
    		}
    		reverse(a,a+m);
    		for(limit=1;limit<=n+m;limit<<=1) ++len;
    		for(int i=0;i<limit;++i) pos[i]=(pos[i>>1]>>1)|((i&1)<<(len-1));
    		for(int i=0;i<m;++i) a1[i]=a[i]*a[i]*a[i];
    		for(int i=0;i<n;++i) b1[i]=b[i];
    		work(a1,b1,1);
    		for(int i=0;i<limit;++i) a1[i]=b1[i]=0;
    		for(int i=0;i<m;++i) a1[i]=a[i]*a[i];
    		for(int i=0;i<n;++i) b1[i]=b[i]*b[i];
    		work(a1,b1,-2);
    		for(int i=0;i<limit;++i) a1[i]=b1[i]=0;
    		for(int i=0;i<m;++i) a1[i]=a[i];
    		for(int i=0;i<n;++i) b1[i]=b[i]*b[i]*b[i];
    		work(a1,b1,1);
    		ntt(c,0);
    		for(int i=m-1;i<n;++i)
    		{
    			if(!c[i]) ret[++num]=i-m+2;
    		}
    		printf("%lld
    ",num);
    		for(int i=1;i<=num;++i) printf("%lld ",ret[i]);
    	}
    }
    signed main()
    {
    	red::main();
    	return 0;
    }
    
  • 相关阅读:
    SplitViewController的简单使用
    ViewController容器
    AnchorPoint 和Position 关系
    __OSX_AVAILABLE_BUT_DEPRECATED
    __OSX_AVAILABLE_STARTING
    UIButton重复点击,重复触发,怎么办
    iOS小技巧:用runtime 解决UIButton 重复点击问题
    FOUNDATION_EXPORT 或#define 或 extern
    nginx第一天
    053-001
  • 原文地址:https://www.cnblogs.com/knife-rose/p/12053200.html
Copyright © 2011-2022 走看看