题目链接:
http://codeforces.com/problemset/problem/577/B
题目大意:
给n个数,问他们之中的某些和能不能被m整除。
思路:
当n>m时,根据鸽巢原理,可以判断一定为YES。因为对于这些数,取模以后的范围为(0,m-1),那么当到第m+1个时候,至少这个取模后的数与前面中的一个有重复,此时肯定有两个相加能被m整除。
当n<=m时,可以考虑用dp,dp[i][j]表示前i个数取模获得j。
代码:
#include<stdio.h>
#include<string.h>
int dp[1005][1005],a[1000005];
int main()
{
int n,m,i,j,k;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i]=a[i]%m;
}
if(n>m)
{
printf("YES\n");
continue;
}
dp[1][a[1]]=1;
for(i=2;i<=n;i++)
{
dp[i][a[i]]=1;
for(j=0;j<m;j++)
{
if(dp[i-1][j]){
dp[i][j]=1;
dp[i][(j+a[i])%m]=1;
}
}
}
if(dp[n][0])printf("YES\n");
else printf("NO\n");
}
}
也可以用set,将所得的和全部加入set中,看最小的那个是否为0.
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
int a[1000005],sum[100005];
int main()
{
int n,m,i,j,k,flag;
set<int>se;
while(scanf("%d%d",&n,&m)!=EOF)
{
flag=0;
memset(sum,0,sizeof(sum));
se.clear();
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i]=a[i]%m;
}
if(n>m){
printf("YES\n");
continue;
}
set<int>::iterator it;
se.insert(a[1]);
for(i=2;i<=n;i++)
{
it=se.begin();
int x=*it;
if(x==0)
{
flag=1;
break;
}
int l=0;
for(it=se.begin();it!=se.end();++it)
{
int x=*it;
sum[l++]=(x+a[i])%m;
}
for(j=0;j<l;j++)
se.insert(sum[j]);
se.insert(a[i]);
}
it=se.begin();
if(*it==0)flag=1;
if(flag)printf("YES\n");
else printf("NO\n");
}
return 0;
}