入阵曲:桶,前缀和

给出的题解不错,所以不写得太详细了。

谁不会60分的那真是没办法了。

1 #include<cstdio>
2 int x[405][405],n,m,k,ans;
3 int main(){
4     scanf("%d%d%d",&n,&m,&k);
5     for(int i=1;i<=n;++i)for(int j=1,y;j<=m;++j)scanf("%d",&y),x[i][j]=(x[i-1][j]+x[i][j-1]-x[i-1][j-1]+y)%k;
6     for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)for(int p=0;p<i;++p)for(int q=0;q<j;++q)if((x[i][j]-x[p][j]-x[i][q]+x[p][q])%k==0)ans++;
7     printf("%d\n",ans);
8 }
考场上秒写的8行60分暴力

看数据范围,有不少测试点m=2。这有什么用?(肯定和同样矩阵大小而mn均匀的点不一样啦)

永远不要忽视测试点的提示作用。NOIP数据范围就很全。

对于只有两行的矩阵,首先我们只选出单独一行的2种,处理它。

接下来就只有两行一起选的问题了。

扩展到更多行,我们可以发现所有行上的选法是m2的。

而如果把每一行的同一列上的数加起来得到新的一行,这就变成了单行上的问题了。

现在我们只需要O(n)求出单行。

刚开始我感觉不可做。但是实际上,这一行的前i位前缀和为sum[i],那么区间l~r能被k整除当且仅当(sum[r]-sum[l-1])%k==0

证明很简单。因为这一段能整除的话,在加上其它的一段值就是后者的值。

所以我们要找满足条件的l-1。也就是给出sum[r]问有多少sum[l-1]满足条件。

开一堆桶buc,buc[p]表示sum[i]%k==p对应的i的个数。每次以r为区间右端点累加答案时直接加上buc[sum[r]]即可。

而且如果一个sum值本身就是k的倍数,那么也要ans++。

 1 #include<cstdio>
 2 int x[405][405],n,m,mod,buc[1000005],l[405];long long ans;
 3 int main(){
 4     scanf("%d%d%d",&n,&m,&mod);
 5     for(int i=1;i<=n;++i)for(int j=1,y;j<=m;++j)scanf("%d",&x[i][j]),(x[i][j]+=x[i][j-1])%=mod;
 6     for(int i=1;i<=n;++i){
 7         for(int j=1;j<=m;++j)l[j]=0;
 8         for(int j=i;j<=n;++j){
 9             for(int k=1;k<=m;++k)(l[k]+=x[j][k])%=mod,ans+=buc[l[k]]+(l[k]?0:1),buc[l[k]]++;
10             for(int k=1;k<=m;++k)buc[l[k]]--;
11         }
12     }
13     printf("%lld\n",ans);
14 }
然而也只有14行

 

转载于:https://www.cnblogs.com/hzoi-DeepinC/p/11335210.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值