前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【CodeForces 577B】Modulo Sum

【CodeForces 577B】Modulo Sum

作者头像
饶文津
发布2020-06-02 11:38:17
3720
发布2020-06-02 11:38:17
举报
文章被收录于专栏:饶文津的专栏饶文津的专栏

题意

给你n(1 ≤ n ≤ 106)个数a1..an(0 ≤ ai ≤ 109),再给你m( 2 ≤ m ≤ 103)如果n个数的子集的和可以被m整除,则输出YES,否则NO。

分析

分两种情况:

  当n>m时,s[i]表示a[i]前缀和,s[i]%m的取值为0到m-1,由抽屉原理/鸽巢原理可知,s[i]一定有重复的,假如重复的是s[l]和s[r],那么s[r]-s[l]也就是l+1到r这些数加起来就是m 的倍数。故答案为YES。

  当n≤m时,我们用dp[i][j]==1表示前i个数可以得到对m取余为j的子集,每次读入一个a,dp[i][a%m]=1;dp[i][j]=max(dp[i-1][j],dp[i-1][(m+j-a[i]%m)%m])(j!=a%m,0≤j<m),也就是多了第i张钱能否得到对m取余为j的价格。一旦得到dp[i][0]==1,答案就是YES就不用继续算了。但是这样太浪费空间了,也开不了那么大数组,i最大为106。只要保存上一次的和这一次的就够了。

  另一种是直接推,根据之前可得到的余数推出这一轮可得到的余数。

代码

dp代码

代码语言:javascript
复制
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,a;
int dp[2][1005];
int main()
{
    scanf("%d%d",&n,&m);
    if(n>m)dp[0][0]=1;
    else
        for(int i=1; i<=n; i++)
        {
            for(int j=0; j<m; j++)dp[1][j]=0;
            scanf("%d",&a);
            dp[1][a%m]=1;

            for(int j=0; j<m; j++)
            {
                if(dp[1][0])break;
                if(j!=a%m)
                    dp[1][j]=max(dp[0][j],dp[0][(m+j-a%m)%m]);
            }
            for(int j=0; j<m; j++)
                dp[0][j]=dp[1][j];
        }
    if(dp[0][0]) printf("YES");
    else printf("NO");
    return 0;
}

另一种代码

思路是mark[i]标记当前所有数余数i能否出现,t[i]记录的之前余数i能否出现。

代码语言:javascript
复制
#include<cstdio>
#include<cstring>
int n,m;
int a;
int mark[1005],t[1005];
int main()
{
    scanf("%d%d",&n,&m);
    if(n>m)t[0]=1;
    else
        while(n--)
        {
            scanf("%d",&a);
            memset(mark,0,sizeof(mark));
            mark[a%m]=1;
            for(int i=0; i<m; i++)
            {
                if(t[0]) break;
                if(t[i]) mark[(a%m+i)%m]=1;
                //如果之前可得到%m=i的价格,那现在就可得到(a%m+i)%m的价格
            }
            for(int i=0; i<m; i++)
            {
                if(t[i]==0) t[i]=mark[i];
                //保存这一轮的。不能合并到上面一起写
            }
        }
    if(t[0]) printf("YES\n");
    else printf("NO\n");
    return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-02-15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题意
  • 分析
  • 代码
    • dp代码
      • 另一种代码
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档