题面
样例输入
5 8
GLGGLGLG
GGLGGLGL
GGLLLGGG
LLGLLGLG
LGGGLGLL
3
2 3
GLL
LGG
3 1
L
G
G
1 4
GGLL
样例输出
1 3
1 2
3 1
数据规模
1 ≤ R , C ≤ 500 , B ≤ 5 1≤R,C≤500,B≤5 1≤R,C≤500,B≤5
题解
看到题解的时候惊了…
二维卷积???
其实也没有那么复杂…
先考虑如何将其转换为一个二维卷积问题。
可以发现,将G
用数字0
代替,L
用数字1
代替,那么现在在农场中选取区域的右下端点
(
p
x
,
p
y
)
(px,py)
(px,py),那么同一个位置都是G
的个数就是每个位置的两个数字值相乘再相加(L
同理),是不是很像卷积?
我们可以从算贡献的角度入手。
可以知道的是:如果在农场和矩阵中分别确定一个点,那么它们一定会给有且只有一个
(
p
x
,
p
y
)
(px,py)
(px,py)做出贡献。
设在农场的大小为
R
∗
C
R*C
R∗C,矩阵的大小为
n
∗
m
n*m
n∗m,在农场选取的点为
(
x
,
y
)
(x,y)
(x,y),在矩阵上选取的点为
(
i
,
j
)
(i,j)
(i,j)。
[由于蒟蒻电脑画图太丑,请大家自行画图观察一下]
它们所做出贡献的点就是
(
n
−
i
−
1
+
x
,
m
−
j
−
1
+
y
)
(n-i-1+x,m-j-1+y)
(n−i−1+x,m−j−1+y)
将其拆成
(
n
−
i
−
1
,
m
−
j
−
1
)
+
(
x
,
y
)
(n-i-1,m-j-1)+(x,y)
(n−i−1,m−j−1)+(x,y)
可以看成是矩阵上下左右翻转后与农场进行卷积。
注意到本质上是一个二元组的一维卷积,不妨将其直接变成
(
n
−
i
−
1
)
∗
R
+
m
−
j
−
1
(n-i-1)*R+m-j-1
(n−i−1)∗R+m−j−1与
x
∗
R
+
y
x*R+y
x∗R+y做一维卷积。
容易发现他们是等价的。
也就是说,将矩阵上下左右翻转后,将每个位置
(
i
,
j
)
(i,j)
(i,j)映射到位置
i
∗
R
+
j
i*R+j
i∗R+j,直接进行一维卷积就好。
复杂度:
O
(
T
∗
R
∗
C
log
R
∗
C
)
O(T*R*C\log{R*C})
O(T∗R∗ClogR∗C)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
#define MAXN 500
#define MAXM 1000000
#define LL long long
#define MOD 998244353
#define G 3
using namespace std;
int n,m,m1,n1,len,T;
char mp[MAXN+5][MAXN+5];
LL ans;int px,py;
typedef LL Ploy[MAXM+5];
Ploy g,l,g1,l1,res;
LL fst_pow(LL a,LL b)
{
LL res=1;
while(b){
if(b&1)res=(1LL*res*a)%MOD;
a=(1LL*a*a)%MOD;
b>>=1;
}
return res;
}
void NTT(Ploy &a,int n,int x)
{
for(int i=0,j=0;i<n;i++)
{
if(i<j)swap(a[i],a[j]);
int k=n>>1;
while(k&&(k&j))j^=k,k>>=1;
j^=k;
}
for(int i=1;i<n;i<<=1)
{
int gn=fst_pow(G,(MOD-1)/(i<<1)),g=1;
if(x==-1)gn=fst_pow(gn,MOD-2);
for(int j=0;j<i;j++,g=(1LL*g*gn)%MOD)
for(int l=j,r=l+i;l<n;l+=(i<<1),r=l+i)
{
int tmp=(1LL*a[r]*g)%MOD;
a[r]=(a[l]-tmp+MOD)%MOD;
a[l]=(a[l]+tmp)%MOD;
}
}
if(x==1)return ;
int ny=fst_pow(n,MOD-2);
for(int i=0;i<n;i++)a[i]=(1LL*a[i]*ny)%MOD;
}
void Cg(Ploy &a,Ploy &b)
{
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
a[i*m+j]=(mp[i][j]=='G');
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
b[i*m+j]=(mp[i][j]=='L');
NTT(a,len,1),NTT(b,len,1);
}
void cal()
{
memset(res,0,sizeof(res));
for(int i=0;i<len;i++)
res[i]=(1LL*g[i]*g1[i]%MOD+1LL*l[i]*l1[i]%MOD)%MOD;
NTT(res,len,-1);
}
int main()
{
freopen("best.in","r",stdin);
freopen("best.out","w",stdout);
scanf("%d%d",&n,&m);
len=1;
while(len<=n*m*2)len<<=1;
for(int i=0;i<n;i++)scanf("%s",mp[i]);
Cg(g,l);
scanf("%d",&T);
while(T--)
{
memset(mp,0,sizeof(mp));
memset(l1,0,sizeof(l1));
memset(g1,0,sizeof(g1));
scanf("%d%d",&n1,&m1);
for(int i=0;i<n1;i++)scanf("%s",mp[i]);
for(int i=0;i<n1;i++)reverse(mp[i],mp[i]+m1);
for(int i=0;i<n1&&i<n1-i-1;i++)swap(mp[i],mp[n1-i-1]);
Cg(g1,l1);
cal();
ans=0;px=-1,py=-1;
for(int i=n1-1;i<n;i++)
for(int j=m1-1;j<m;j++)
if(px==-1||ans<res[i*m+j]){
ans=res[i*m+j];
px=i-n1+2,py=j-m1+2;
}
printf("%d %d\n",px,py);
}
}