题目链接:http://codeforces.com/problemset/problem/577/B
题目描述
给你一个长度为 (n) 的数组 (a) : (a_1,a_2, cdots ,a_n),和一个整数 (m) 。
请问能否从数组 (a) 中找出一些元素,使得这些元素的和恰好能被 (m) 整除。
输入格式
输入的第一行包含两个整数 (n) 和 (m) ( (1 le n le 10^6,2 le m le 10^3) ),分别表示数组 (a) 中元素的个数 和 需要被整除的那个数。
输入的第二行包含 (n) 个整数 (a_1, a_2, cdots , a_n) 。( (1 le ai le 10^9) )
输出格式
如果能够从数组 (a) 中找出一些元素,使得这些元素的和恰好能被 (m) 整除,则输出 “YES”;否则输出“NO”。
样例输入1
3 5
1 2 3
样例输出1
YES
样例输入2
1 6
5
样例输出2
NO
样例输入3
4 6
3 1 1 3
样例输出3
YES
样例输入4
6 6
5 5 5 5 5 5
样例输出4
YES
样例解释
样例1中选择 (2+3) 能被 (5) 整除。
样例3中选择 (3+3) 能被 (6) 整除。
样例4中选择 (5+5+5+5+5+5) 能被 (6) 整除。
问题分析
对于这道题目我们可以用动态规划来做。
(f[i][j]) 用于表示到第 (i) 个数的时候,是否存在模 (m) 余 (j) 的方案存在。
如果方案存在,则 (f[i][j]) 为 (true) , 否则 (f[i][j]) 为 (false) 。
所以如果 (f[i-1][j] = true) ,则 (f[i][(j+a[i])%m] = true) 。
同时 (f[i][ a[i] ] = true) 。
但是这道题目的范围 (i) 最大可能是 (^9) ,(j) 最大可能是 (10^3) ,如果开一个这么大的数组肯定不行。
所以我们可以开一个滚动数组 (f[2][1001]) 就可以实现这个效果。
我这里滚动数组的实现时开了两个数组 (vis[]) 和 (tmp[]) 效果也是一样的。
实现代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
int n, m, a;
bool vis[maxn], tmp[maxn];
int main() {
cin >> n >> m;
while (n --) {
cin >> a;
a %= m;
fill(tmp, tmp+m, false);
for (int i = 0; i < m; i ++) if (vis[i]) tmp[(i+a)%m] = true;
for (int i = 0; i < m; i ++) if (tmp[i]) vis[i] = true;
vis[a] = true;
if (vis[0]) {
puts("YES");
return 0;
}
}
puts("NO");
return 0;
}