• 【DP】:CF #319 (Div. 2) B. Modulo Sum


    【题目链接】:http://codeforces.com/contest/577/problem/B

    【相似题目】:http://swjtuoj.cn/problem/2383/

    【题意】:给出n个数,问是否能从中选出一些数,使得这些数的和是m的倍数。

    【题解】:

    首先,先明白这样一个事实:

    设:sum%dend=rem;

    (sum:一些数的和,dend:被除数,rem:余数)

    则有:(rem+n)%dend=(sum+n)%dend;

    (n为一个新的数)

     

    知道了上面的等式之后,题目就好做了:

    设:est[rem]=1 表示存在余数rem,它是通过一些数的和sum%dend得到的。

    对于每一个给定的n,

    考察 1<=rem<=dend-1 范围内的est[rem],即考察是否存在之前一些数的和sum%dend=rem(不管sum是之前的数是怎么相加得来的)

    若存在,即est[rem]=1,则可以通过(rem+n)%dend来求出新的余数,即令est[(rem+n)%dend]=1;

    此外,n%dend也是新的余数,即est[n%dend]=1;

    若在上面的余数中有一个等于0,即est[0]=1,则说明存在dend的倍数,直接中断循环。

     

    【注意】

    在对每一个n的循环中,不能立刻更新est数组,原因是某些情况会导致出错。

    出错例子:

    设:已有est[1]=1,此时n=1,dend=100;

    若令est[(1+n)%dend]=1,即est[2]=1,

    则又有est[(2+n)%dend]=1,即est[3]=1,

    又有est[(3+n)%dend]=1,即est[4]=1......

    最后整个est数组都为1,显然这是错误的。

    所以,要一个 i_est 数组来临时更新est数组,最后再更新est数组(详见代码)。

     1 #include<stdio.h>
     2 int num,dend,t,i,n[1000050];
     3 char est[1050],i_est[1050];
     4 int main(){
     5     scanf("%d%d",&num,&dend);
     6     for(t=0;t<num;t++){
     7         scanf("%d",&n[t]);
     8     }
     9     for(t=0;t<num;t++){
    10         for(i=1;i<dend;i++){
    11             if(!est[i]) continue;
    12             i_est[(i+n[t])%dend]=1;
    13         }
    14         i_est[n[t]%dend]=1;
    15         for(i=0;i<dend;i++){
    16             est[i]=i_est[i];
    17         }
    18         if(est[0]) break;
    19     }
    20     if(est[0]){
    21         printf("YES
    ");
    22     }
    23     else{
    24         printf("NO
    ");
    25     }
    26     return 0;
    27 }
    View Code
  • 相关阅读:
    ACMer第7天Falling Ants
    贪心初步-FatMouse' Trade
    贪心初步-A
    ACM集训第二天
    asp.net中遍历套用母版页的页面的控件
    a 标签中调用js的几种方法
    笔记
    html控件和web控件
    ASP.NET中GUID类
    (转)常见邮件服务器(接收服务器和发送邮件服务器)地址
  • 原文地址:https://www.cnblogs.com/hkxy125/p/6852755.html
Copyright © 2020-2023  润新知