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;
}
posted @ 2021-04-29 22:08  这知识他不进我的脑子  阅读(112)  评论(0编辑  收藏  举报