• 4.28 省选模拟赛模拟赛 最佳农场 二维卷积 NTT


    avatar
    avatar

    第一次遇到二维卷积 不太清楚是怎么做的。

    40分暴力比对即可。

    对于行为或者列为1时 容易想到NTT做快速匹配.然后找答案即可。

    考虑这是一个二维的比对过程。

    (f_{i,j})表示以i,j为右下角的答案。

    那么我们把询问矩阵给上下翻转 左右翻转。设初始矩阵为a 询问矩阵为b 且询问矩阵大小为x,y.

    那么显然有 (f_{i,j}=sum_{l=1}^xsum_{r=1}^y[b_{l,r}==a_{i-l+1,j-r+1}])

    这是一个二维卷积的形式 还是考虑转换成一维卷积的形式。

    一种构造方法 将询问矩阵扩展成原来矩阵大小的矩阵 那么空位补0.

    然后把矩阵按照 i*m+j的编号放下来 做卷积即是(f_{i,j})的答案。

    容易发现是正确。

    const int MAXN=510,N=600000,G=3;
    int g[N],f[N],rev[N],g1[N],f1[N],w[N];
    char a[MAXN][MAXN];
    int n,m,lim=1,Q;
    inline int ksm(int b,int p)
    {
    	int cnt=1;
    	while(p)
    	{
    		if(p&1)cnt=(ll)cnt*b%mod;
    		b=(ll)b*b%mod;p=p>>1;
    	}
    	return cnt;
    }
    inline void NTT(int *a,int op)
    {
    	rep(1,lim-1,i)if(i<rev[i])swap(a[i],a[rev[i]]);
    	for(int len=2;len<=lim;len=len<<1)
    	{
    		int mid=len>>1;
    		int wn=ksm(G,op==1?(mod-1)/len:mod-1-(mod-1)/len);
    		for(int j=0;j<lim;j+=len)
    		{
    			int d=1;
    			for(int i=0;i<mid;++i)
    			{
    				int x=a[i+j],y=(ll)a[i+j+mid]*d%mod;
    				a[i+j]=(x+y)%mod;a[i+j+mid]=(x-y+mod)%mod;
    				d=(ll)d*wn%mod;
    			}
    		}
    	}
    	if(op==-1)
    	{
    		int INV=ksm(lim,mod-2);
    		rep(0,lim-1,i)a[i]=(ll)a[i]*INV%mod;
    	}
    }
    inline void prepare(int *g,int *f)
    {
    	rep(1,n,i)rep(0,m-1,j)
    	g[(i-1)*m+j]=(a[i][j]=='G'),f[(i-1)*m+j]=(a[i][j]=='L');
    	NTT(g,1);NTT(f,1);
    }
    inline void calc()
    {
    	rep(0,lim-1,i)w[i]=((ll)g[i]*g1[i]+(ll)f[i]*f1[i])%mod;
    	NTT(w,-1);
    }
    int main()
    {
    	freopen("best.in","r",stdin);
    	freopen("best.out","w",stdout);
    	gt(n);gt(m);
    	rep(1,n,i)gc(a[i]);
    	int ww=n*(m-1);
    	while(lim<ww+ww)lim=lim<<1;
    	rep(0,lim-1,i)rev[i]=rev[i>>1]>>1|((i&1)?lim>>1:0);
    	prepare(g,f);gt(Q);
    	rep(1,Q,cc)
    	{
    		int x,y;
    		gt(x);gt(y);
    		memset(a,0,sizeof(a));
    		memset(f1,0,sizeof(f1));
    		memset(g1,0,sizeof(g1));
    		rep(1,x,j)gc(a[j]),reverse(a[j],a[j]+y);
    		//rep(1,x,j)printf("%s
    ",a[j]);
    		rep(1,x/2,j)rep(0,y-1,k)swap(a[j][k],a[x-j+1][k]);
    		//rep(1,x,j)printf("%s
    ",a[j]);
    		prepare(g1,f1);
    		calc();
    		//rep(0,ww,j)put(w[j]);
    		int ans=0,ansl=1,ansr=1;
    		rep(x,n,i)
    		{
    			rep(y-1,m-1,j)
    			{
    				if(ans<w[(i-1)*m+j])
    				{
    					ans=w[(i-1)*m+j];
    					ansl=i-x+1;ansr=j+1-y+1;
    				}
    			}
    		}
    		printf("%d %d
    ",ansl,ansr);
    	}
    	return 0;
    }
    
  • 相关阅读:
    js上移、下移排序 效果
    如何为平板打造完美的网站页面?
    [BUUOJ]刮开有奖reverse
    [0CTF 2016]piapiapia
    [TSCTFJ 2019]bypass
    [安洵杯 2019]easy_serialize_php
    [TSCTFJ] relax
    c#访问网页
    DNN 数据访问
    c#访问数据库
  • 原文地址:https://www.cnblogs.com/chdy/p/12805233.html
Copyright © 2020-2023  润新知