• 洛谷P3941入阵曲


    题面:

    题意:

      给你一个的$n*m$矩阵,每个格子里都有一个不超过$k$的正整数。询问这个矩阵里有多少个不同的子矩形中的数字之是$k$的倍数?

    题解:

      我们先考虑一个简化版的一维问题:给定一个长度为$n$的序列,$a[1],a[2],cdots,a[n]$,如果某一段子序列的和为$k$的倍数,则称其为$k$倍区间,求该序列中有多少个$k$倍区间,要求时间复杂度为$O(n)$。

      设$sum$为该序列的前缀和,那么若$(sum[r]-sum[l-1])%k==0$,则区间$[l,r]$符合条件,但暴力枚举复杂度为$O(n^2)$,不符合条件。

      考虑优化,将上式变形后为$sum[l-1]%k==sum[r]%k$,所以我们可以用桶来处理在$i$之前前缀和为$sum[i]$的数量。

      继续考虑原问题,我们可以枚举两行,再枚举列,把这一列合为一个数,即可用上述方法解决。

    code:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define R register
    #define ll long long
    inline ll read(){
    	ll aa=0;R int bb=1;char cc=getchar();
    	while(cc<'0'||cc>'9')
    		{if(cc=='-')bb=-1;cc=getchar();}
    	while(cc>='0'&&cc<='9')
    		{aa=(aa<<1)+(aa<<3)+(cc^48);cc=getchar();}
    	return aa*bb;
    }
    const int N=403;
    const int M=1e6+3;
    int n,m,mod,sum[N][N],a[N];
    ll ans,cnt[M];
    int main()
    {
    	n=read();m=read();mod=read();
    	for(R int i=1,num;i<=n;++i){
    		num=0;
    		for(R int j=1,x;j<=m;++j){
    			x=read(); num+=x;
    			if(num>=mod)num-=mod;
    			sum[i][j]=num+sum[i-1][j];
    			if(sum[i][j]>=mod)sum[i][j]-=mod;
    		}
    	}
    	for(R int i=1;i<=n;++i){
    		for(R int j=i;j<=n;++j){
    			//cnt[0]=1;
    			for(R int k=1;k<=m;++k){
    				a[k]=(sum[j][k]-sum[i-1][k]+mod)%mod;
    				ans+=cnt[a[k]];
    				++cnt[a[k]];
    			}
    			ans+=cnt[0];
    			//可理解为加上本来就为k的倍数的区间个数,可写成上述注释。
    			for(R int k=1;k<=m;++k)cnt[a[k]]=0;
    		}
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    P2617 Dynamic Rankings[带修主席树(模板)]
    P2617 Dynamic Rankings[带修主席树(模板)]
    P4127 [AHOI2009]同类分布
    P4127 [AHOI2009]同类分布
    P4550 收集邮票 [期望dp]
    P4550 收集邮票 [期望dp]
    P3168 [CQOI2015]任务查询系统
    蓝桥杯 2的次幂表示 递归
    蓝桥杯 最大的算式 dp
    蓝桥杯 未名湖边的烦恼 递推 dp
  • 原文地址:https://www.cnblogs.com/toot-wjh/p/11336436.html
Copyright © 2020-2023  润新知