You are given a sequence of numbers a1, a2, ..., an, and a number m.
Check if it is possible to choose a non-empty subsequence aij such that the sum of numbers in this subsequence is divisible by m.
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 a1, a2, ..., an (0 ≤ ai ≤ 109).
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.
3 5
1 2 3
YES
1 6
5
NO
4 6
3 1 1 3
YES
6 6
5 5 5 5 5 5
YES
In the first sample test you can choose numbers 2 and 3, the sum of which is divisible by 5.
In the second sample test the single non-empty subsequence of numbers is a single number 5. Number 5 is not divisible by 6, that is, the sought subsequence doesn't exist.
In the third sample test you need to choose two numbers 3 on the ends.
In the fourth sample test you can take the whole subsequence.
鸽巢原理,不管怎么排,我们对数列求前缀和,在求模后得到pre1 , pre2 ,pre3 ,……pren,因为n>m,必存在prei = prej (i != j), 然后 (prei - prej) = 0 (mod m) 。
所以n>m时,为O(1)
然后剩下的部分n<=m时,用O(m*m)的dp即可。
然而没有我没有考虑鸽巢原理,用O(n*m)的dp加剪枝也过了,,,,,写dp要养成一个好习惯,那就是用当前的 已知解 去推 未知解 ,(反过来的话会碰上一些意想不到的问题),并且这样会自然形成一个剪枝
#include<bits/stdc++.h> using namespace std; typedef long long ll ; const int M = 1e6 + 10 ; int vis[1000 + 10] ; ll pre[M] ; int n , m ; int dp[1000 + 10] ; int d[1000 + 10] ; int main () { scanf ("%d%d" , &n , &m) ; bool flag = 0 ; for (int i = 1 ; i <= n ; i ++) { int x ; scanf ("%d" , &x) ; x = x % m ; if (x == 0) flag = 1 ; vis[x] ++ ; } if (flag) { puts ("YES") ; return 0 ; } int tmp = -1 ; dp[0] = 1 ; while (vis[++tmp] == 0 && tmp <= 1000) ; //printf ("%d : num(%d) " , tmp , vis[tmp]) ; for (int i = 1 ; i <= vis[tmp] ; i ++) { int ans = tmp*i%m ; if (ans == 0) ans = m ; dp[ans] = m ; } if (dp[m]) { puts ("YES") ; return 0; } for (int i = tmp+1 ; i <= m ; i ++) { if (vis[i] == 0) continue ; //printf ("%d : num(%d) " , i , vis[i]) ; for (int i = 0 ; i <= m ; i ++) d[i] = dp[i] ; for (int j = 0 ; j <= m ; j ++) { if (d[j] == 0) continue ; for (int k = 1 ; k <= vis[i] ; k ++) { int ans = (j+i*k)%m ; if (ans == 0) ans = m ; dp[ans] = 1 ; } } if (dp[m]) { puts ("YES") ; return 0 ; } } //for (int i = 1 ; i <= m ; i ++) printf ("%d " , dp[i]) ; puts ("") ; puts ("NO") ; return 0 ; }