cf577 B. Modulo Sum - 鹊巢定理 + 01背包
给出\(n\)个数字,任取一个集合,是否存在一个集合的和是\(m\)的倍数
我求出前缀和,同时对m取模,如果说\(n>m\),根据鹊巢定理那么必定存在两个前缀和的模是相等的。
然后只需要对于\(n<1000,m<1000\),进行\(n^2\)的\(01\)背包去跑即可
定义\(dp[i][j]\)表示取到第\(i\)个物品时,大小为\(j\)的情况是否存在。
初始化\(dp[i][a[i]] = 1\)
转移方程\(dp[i][j] |= dp[i - 1][j]\), \(dp[i - 1][j + a[i]] |= dp[i - 1][j]\)
就是01背包的本质吧
int a[N];
bool dp[N][N];
void solve(int kase){
int n, m;
scanf("%d%d", &n, &m);
if(n > m) {
printf("YES\n"); return;
}
bool f = 0;
for(int i = 1; i <= n; i++) scanf("%d", &a[i]), f = a[i] == m, a[i] %= m;
if(f) {
printf("YES\n"); return;
}
for(int i = 1; i <= n; i++) {
dp[i][a[i]] = 1;
for(int j = 0; j < m; j++) {
dp[i][j] |= dp[i - 1][j];
dp[i][(j + a[i]) % m] |= dp[i - 1][j];
}
}
printf("%s\n", dp[n][0] ? "YES" : "NO");
}
I‘m Stein, welcome to my blog