0
点赞
收藏
分享

微信扫一扫

CF577B Modulo Sum 题解 动态规划

题目链接:​​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;
}


举报

相关推荐

0 条评论