AtCoder Beginner Contest 461-D二维数组压维+前缀和计数

题意:对于一个二维数组,看有多少个矩形的元素之和是k

思路:记录列前缀和,最后枚举矩形的上下边界,进行i到j行的一维前缀和计数

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define endl '\n'
using namespace std;
typedef pair<int,int> pii;
const int N=1e6+10;
const int mod=998244353;
vector<int>pm;
int judge[N],nm[N],inv[N];
int Log2[N];
int kmi(int a,int b){
    int res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
void init(){
    nm[0]=inv[0]=1;
    for(int i=1;i<=1e6;i++){
        nm[i]=nm[i-1]*i%mod;
        inv[i]=kmi(nm[i],mod-2);
    }
}
void euler(int n){
    judge[1]=1;
    for(int i=2;i<=n;i++){
        if(!judge[i]){
            pm.push_back(i);
        }
        for(int j=0;pm[j]*i<=n;j++){
            judge[pm[j]*i]=1;
            if(i%pm[j]==0) break;
        }
    }
}
int C(int a,int b){
    return nm[a]*inv[a-b]%mod*inv[b]%mod;
}

void solve(){
    int n,m,k;cin>>n>>m>>k;
    vector<vector<int> >a(n+10,vector<int>(m+10));
    vector<vector<int> >pre(n+10,vector<int>(m+10));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            char c;cin>>c;
            a[i][j]=c-'0';
            pre[i][j]=pre[i-1][j]+a[i][j];
        }
    }
    vector<int>cnt(3e5+10);
    int ans=0;
    for(int u=1;u<=n;u++){
        for(int d=u;d<=n;d++){
            int now=0;
            cnt[0]=1;
            set<int>del;
            for(int j=1;j<=m;j++){
                int t=pre[d][j]-pre[u-1][j];
                now+=t;
                if(now-k>=0)ans+=cnt[now-k];
                cnt[now]++;
                if(cnt[now]==1) del.insert(now);
            }
            for(auto x:del) cnt[x]=0;
        }
    }
    cout<<ans;
}
signed main(){
    ios::sync_with_stdio(0);cin.tie(0);
     for(int i=2;i<=1e6;i++){
        Log2[i]=Log2[i/2]+1;
    }
    int T=1;//cin>>T;
    while(T--) solve();
    return 0;
}