[ABC331D] Tile Pattern
思路
其实挺一眼的吧。我们其实很容易找出规律,如果对于一块矩阵我们可以分成四个部分,如下图。

这里我们可以用到一种前缀和相减的思想,将总的算出来再减去多余的。
然后我们只需要分别算贡献即可。
-
首先是 A 部分,我们可以发现就是对于一个矩阵中与原矩阵可完全覆盖的位置,那么就是原矩阵的贡献乘上 \(\lfloor\frac{l}{n}\rfloor\times\lfloor\frac{r}{n}\rfloor\),这个应该很好理解。
-
对于 B 部分我们可以发现其实高和 A 是一样的,那么只需要求长即可,就为 \(S_{0,0,(l+1)\bmod n-1,n-1}\times \lfloor\frac{r}{n}\rfloor\) 这里的 \(S_{a,b,c,d}\) 表示原矩阵从 \(a,b\) 到 \(c,d\) 的总贡献。
-
对于 C 部分,我们可以用与 B 部分同理的方法解决,最后可得出贡献为 \(S_{0,0,n-1,(r+1)\bmod n-1}\times \lfloor\frac{l}{n}\rfloor\)。
-
对于最后的 D 部分,可以发现其长和宽分别和 B 和 C 部分相同那么也很容易得出公式为 \(S_{0,0,(l+1)\bmod n-1,(r+1)\bmod n-1}\)。
那么我们根据前缀和的思想可以得出对于一个矩阵 \(a,b,c,d\) 其答案为 \(A_{c,d}-A_{a-1,d}-A_{c,b-1}+A_{a-1,b-1}\),这里的 \(A_{i,j}\) 表示为从大矩阵的 \(0,0\) 到 \(i,j\) 的数量和。
代码
其实也挺短的。
#include <bits/stdc++.h>
using namespace std ;
#define int long long
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define rep1(i,x,y) for(int i=x;i>=y;i--)
#define fire signed
#define kong putchar(' ')
#define end putchar('\n')
#define in(x) scanf("%lld",&x)
#define lcm(x,y) x*y/__gcd(x,y)
#define il inline
il void print(int x) {
if(x>=10) print(x/10);
putchar(x%10+'0');
}
const int N=1e3+10;
int n,m;
int c[N][N],cnt;
char ma[N][N];
int s(int x,int y) {
if(x<0||y<0||x>=n||y>=n) return 0;
return c[x][y];
}
int k(int a,int b,int c,int d) {
return s(c,d)-s(a-1,d)-s(c,b-1)+s(a-1,b-1);
}
int q(int x,int y) {
if(x<0||y<0) return 0;
int tot=(x+1)/n,to=(y+1)/n;
int res=cnt*tot*to;
int t1=(x+1)%n-1,t2=(y+1)%n-1;
res+=to*k(0,0,t1,n-1)+tot*k(0,0,n-1,t2)+k(0,0,t1,t2);
return res;
}
fire main() {
in(n),in(m);
rep(i,0,n-1) rep(j,0,n-1) cin>>ma[i][j],c[i][j]=(ma[i][j]=='B');
rep(i,0,n-1) rep(j,0,n-1) c[i][j]+=s(i-1,j)+s(i,j-1)-s(i-1,j-1);
cnt=s(n-1,n-1);
while(m--) {
int a,b,c,d;
cin>>a>>b>>c>>d;
cout<<q(c,d)-q(a-1,d)+q(a-1,b-1)-q(c,b-1)<<endl;
}
return false;
}

浙公网安备 33010602011771号