首页 > 其他 > 详细

LuoguP3941 将军令

时间:2019-10-23 00:01:08      阅读:127      评论:0      收藏:0      [点我收藏+]

LuoguP3941 将军令

题面

链接

题解

简化问题如果求一个数列上有几段的和为K的倍数,容易想到记录一下前缀和,前缀和在膜K相同则为一组解

 

考虑二维枚举开始行和结束行,讲其转化为一维的问题

 

然后开个桶记录一下,注意对于不同的开始行和结束的列到最后要撤销,而不是直接清零

 

因为K可能很大,清零的话就会消耗太多时间(可以类比CDQ分治撤销树状数组)

 

最开始直接清零的,T飞了

 

#include<bits/stdc++.h>

using namespace std;

#define LL long long

inline LL read()
{
    LL f = 1,x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == -) f=-1;
    }while(ch<0||ch>9);
    do
    {
        x = (x<<3) + (x<<1) + ch - 0;
        ch = getchar();
    }while(ch>=0&&ch<=9);
    return f*x;
}

const int MAXN = 400 + 5;

long long n,m,k;
int a[MAXN][MAXN];
long long sum[MAXN][MAXN];
long long ton[1000000 + 10];
long long b[MAXN];

int main()
{
    n=read(),m=read(),k=read();
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            a[i][j]=read();a[i][j]%=k;
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            sum[i][j] = sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]+k;
            sum[i][j] %= k;
    //        cout<<sum[i][j]<<endl;
        }
    }
    long long ans = 0;

    for(int i=0;i<n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
             ton[0]=1;
             for(int h=1;h<=m;h++)
             {
                 b[h] = (sum[j][h]-sum[i][h]+k)%k;
                 ans+=ton[b[h]];
                 ton[b[h]]++;
             }
             for(int h=1;h<=m;h++) ton[b[h]]=0;     
        }
    }
    cout<<ans<<endl;
}

 

LuoguP3941 将军令

原文:https://www.cnblogs.com/wlzs1432/p/11723506.html

(1)
(1)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!