CF 557B. Modulo Sum【抽屉原理】
题目链接
思路
当\(n>m\)时一定存在一个子序列的和%\(m\)为0。
证明:
考虑每一位的前缀和,那么一共\(n\)位前缀和,每一位从1到n的前缀和的范围在\([0,m)\),根据抽屉原理(把多于n个的物体放到n个抽屉里,则至少有一个抽屉里的东西不少于两件)可得:在\(sum_1\)到\(sum_n\)中至少有两个值是相同的。那么这就表示这两个数区间和%m为0。就找到了这样的一个子序列和。
对于剩下m = 1000 dp即可。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 1000 + 10;
bool f[N][N];
int a[N];
void solve() {
int n, m;
scanf("%d%d", &n, &m);
if(n > m) {
puts("YES");
return;
}
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
a[i] %= m;
}
f[0][0] = true;
for(int i = 1; i <= n; i++) {
for(int j = 0; j <= m; j++) {
if((j + a[i]) % m == 0 && f[i - 1][j]) {
f[i][m] = true;
}
else {
f[i][(j + a[i]) % m] |= f[i - 1][j];
f[i][j] |= f[i - 1][j];
}
}
}
if(f[n][m]) puts("YES");
else puts("NO");
}
int main() {
// freopen("in.txt", "r", stdin);
solve();
return 0;
}