zoukankan      html  css  js  c++  java
  • 洛谷P3941入阵曲

      题目传送门

      这道题也是今年湖南集训队Day8的第一题,昨天洛谷的公开赛上又考了一遍,来发个记录(其实是因为五月天,另外两道题分别是将军令和星空,出这次题目的人肯定同为五迷(✪㉨✪))

      话不多说。先理解下题意,给定一个n*m的矩阵,要求出能被k整除的子矩阵个数。

      题意很简单,但是矩阵这方面的题目一直是我最大的软肋,所以昨天做的时候就直接交了个O( n^2 m^2 )的暴力,然后运气还可以,水了60分(据说暴力只有55?)然后在网上看到某集训队大犇的解题报告,搞懂了这题的正解做法。

      那位大犇的做法是O( n^2 m )的,用读优可以卡过去,虽然我也想能不能还优化一下,但是无奈蒟蒻怎能比肩大犇QAQ

      为了优化时间复杂度,在读入的时候就用一个二维数组记录下前缀和(用融斥原理),之后n^2枚举纵列起点和终点,然后枚举横列,用两个数组计数,当然其中也还有一些非常玄学的做法,具体还是看代码吧,在代码里解释:

    #include<bits/stdc++.h>
    #define ll long long//切记要开long long;
    #define maxn 405
    using namespace std;
    ll n,m,mod,a[maxn][maxn];
    ll sum[maxn][maxn],ans;
    ll b[maxn],cnt[1000010];
    inline ll read()
    {
      char ch=getchar();ll num=0;bool flag=false;
      while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}
    //这里要注意要用while,一开始我用if被卡了四个点,非常玄学,可能是输入数据有毒; while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();} return flag?-num:num; } int main() { //freopen("water.in","r",stdin); n=read();m=read();mod=read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ a[i][j]=read(); sum[i][j]=(sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]); if(sum[i][j]>=mod)sum[i][j]-=mod;} //这里是一个小技巧,当sum已经大于mod时直接减去,可以缩小操作时的数据范围,对结果不影响,可以达到优化的效果; for(int i=0;i<n;++i){ for(int j=i+1;j<=n;++j){ cnt[0]=1;//别忘了初始化; for(int k=1;k<=m;++k){ b[k]=(sum[j][k]-sum[i][k])%mod; //这里自己好好理解下,为什么这么做可行;   if(b[k]<0)b[k]+=mod; ans+=cnt[b[k]]; ++cnt[b[k]]; } for(int k=1;k<=m;++k)cnt[b[k]]=0; //每次做完以后还原数组; } } printf("%lld ",ans); return 0; }

      最后再放上炒鸡好听的入阵曲~~为我五团疯狂打call!!!!!

    蒟蒻写博客不易,如果有误还请大佬们提出
    如需转载,请署名作者并附上原文链接,蒟蒻非常感激
    名称:HolseLee
    博客地址:www.cnblogs.com/cytus
    个人邮箱:1073133650@qq.com
  • 相关阅读:
    八数码难题 (codevs 1225)题解
    小木棍 (codevs 3498)题解
    sliding windows (poj 2823) 题解
    集合删数 (vijos 1545) 题解
    合并果子 (codevs 1063) 题解
    等价表达式 (codevs 1107)题解
    生理周期 (poj 1006) 题解
    区间 (vijos 1439) 题解
    区间覆盖问题 题解
    种树 (codevs 1653) 题解
  • 原文地址:https://www.cnblogs.com/cytus/p/7776410.html
Copyright © 2011-2022 走看看