思路:子序列和是经典的背包问题,但对于这题来说,因为和太大了,需要进一步思考.考虑
m
m
m很小,应当从这点入手,我们只考虑是否有子序列之和
%
m
为
0
\%m为0
%m为0
那么我们考虑对所有的子序列和模
m
m
m。
此时需要一点灵感,因为即使这样,背包空间是m,物品数量是n,这么做仍然是会超时的.此时,标签中的鹊巢原理就出现作用了,思考,当n>m,时,有大于m件的物品放入m个抽屉中,一定会出现两个值相同的情况,只需取n<m的情况就可以了.
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3+5;
const int INF = 1e9+7;
typedef long long ll;
typedef pair<int,int> pii;
#define all(a) (a).begin(), (a).end()
#define pb(a) push_back(a)
vector<int> G[maxn];
//前向星
// for(int i=head[u];i!=-1;i=nxt[i]) v = to[i]
//int nxt[maxn],head[maxn],to[maxn];// head[u],cnt 初始值是-1
//int tot = -1;
//void add(int u,int v){
// nxt[++tot] = head[u];
// head[u] = tot;
// to[tot] = v;
//}
bool dp[maxn][maxn];int a[maxn];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,m;cin>>n>>m;
if(n>m){
cout<<"YES\n";
exit(0);
}
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) a[i]%=m;
bool ok = false;
for(int i=1;i<=n;i++){
dp[i][a[i]] = 1;
for(int j=1;j<=m;j++){
dp[i][j]|=dp[i-1][j];
dp[i][(j+a[i])%m]|=dp[i-1][j];
}
ok|=dp[i][0];
}
if(ok) cout<<"YES\n";
else cout<<"NO\n";
}