【题解】洛谷 P3941 入阵曲【20201017 CSP 模拟赛】
题意
给定 \(n\times m\) 的矩阵,问有多少个子矩阵的和是 \(k\) 的倍数。\(n,m\leq 400\)。
题解
预处理每一行的前缀和。枚举矩形左右是哪两列,用桶记录前 \(i\) 行的前缀和模 \(k\) 的值。时间复杂度 \(O(nm^2)\)。
注意减了之后取模可能有负数。
#include<bits/stdc++.h>
using namespace std;
const int LEN=1e6;
char buf[LEN+10],*PT=buf+LEN;
inline char gc(){
return (PT==buf+LEN)?(fread(buf,1,LEN,stdin),PT=buf,*(PT++)):*(PT++);
}
inline int getint(){
int ans=0;
char c=gc();
while(c<'0'||c>'9')c=gc();
while(c>='0'&&c<='9'){
ans=ans*10+c-'0';
c=gc();
}
return ans;
}
const int N=410;
int n,m,k,a[N][N];
int b[N][N],c[1000100];
int _(int x){ return x>=k?x-k:x; }
int main(){
n=getint(),m=getint(),k=getint();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]=getint();
b[i][j]=_(b[i][j-1]+a[i][j]);
}
}
long long ans=0;
for(int i=0;i<m;i++){
for(int j=i+1;j<=m;j++){
c[0]++;
int s=0;
for(int l=1;l<=n;l++){
int t=_(b[l][j]-b[l][i]+k);
s=_(s+t);
ans+=c[s];
c[s]++;
}
s=0;
for(int l=1;l<=n;l++){
int t=_(b[l][j]-b[l][i]+k);
s=_(s+t);
c[s]=0;
}
c[0]=0;
}
}
cout<<ans;
}