第一次遇到二维卷积 不太清楚是怎么做的。
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;
}