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");
}
posted @ 2021-01-02 10:21  Emcikem  阅读(76)  评论(0编辑  收藏  举报