Codeforces 577B. Modulo Sum (数学 + DP)

Description
You are given a sequence of numbers a 1, a 2, …, a n, and a number m.

Check if it is possible to choose a non-empty subsequence a i j such that the sum of numbers in this subsequence is divisible by m.

Input
The first line contains two numbers, n and m (1 ≤ n ≤ 106, 2 ≤ m ≤ 103) — the size of the original sequence and the number such that sum should be divisible by it.

The second line contains n integers a 1, a 2, …, a n (0 ≤ a i ≤ 109).

Output
In the single line print either “YES” (without the quotes) if there exists the sought subsequence, or “NO” (without the quotes), if such subsequence doesn’t exist.

Examples
Input
3 5
1 2 3
Output
YES

Input
1 6
5
Output
NO

Input
4 6
3 1 1 3
Output
YES

Input
6 6
5 5 5 5 5 5
Output
YES

Solution
有n个数,问是否能选出若干数,其和为m的倍数

首先肯定考虑直接背包,但时间复杂度 O ( n ∗ m ) O(n*m) O(nm) 显然不行
发现当 n > m n > m n>m 时答案肯定为YES,粗略证明如下:

假设当 n > m 不存在若干数的和为m的倍数
则前 [1, m] 个数的前缀和%m 一定互不相同 (否则就可以选出一段连续的数和 % m = = 0 \%m == 0 %m==0)
即一共有 m m m 种不同的前缀和 占满了 0 ~ (m-1)
故第 m + 1 m + 1 m+1 个数的前缀和一定会与之前的相同,所以必能选出一段和 % m = = 0 \%m == 0 %m==0

所以背包复杂度实际为 O ( m ∗ m ) O(m*m) O(mm)

Code

int a[maxn];
bool dp[maxn][2];
int main() {
	int n,m;scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;++i){
		scanf("%d",&a[i]); a[i]%=m;
	}
	if(n > m) {printf("YES\n");return 0;}
	int op = 0;
	for(int i = 1;i <= n;++i){
		op ^= 1;
		for(int j = 0;j < m;++j) dp[j][op] = dp[j][op^1];
		dp[a[i]][op] = true;
		for(int j = 0;j < m;++j){
			if(dp[j][op^1]) dp[(j+a[i])%m][op] = true;
		}
	}
	if(dp[0][op]) printf("YES\n"); else printf("NO\n");
    return 0;
}
©️2020 CSDN 皮肤主题: 像素格子 设计师:CSDN官方博客 返回首页