https://codeforces.com/contest/577/problem/B
题意:给定长度为n个数组和一个m(1 <= n <= 1e6, 2 <= m <= 1e3),其中n中的元素(1 <= x <= 1e9)。问n中是否有子序列的和可以被m整除,输出YES或NO。
思路:维护一个集合,依此遍历数组元素,每次遍历将集合中的元素进行更新,更新过程中看是否有0出现即可。
总结:m范围为1e3,n的范围为1e6,考虑对n中的元素取模,使用背包暴力求解时间复杂度是1e6 * 1e3 = 1e9。但是背包的最大容量为1e3,在遍历每个元素的过程中进行了大量的重复和无用计算,我们只关心是否0容量会出现。 所以直接使用std::set来维护已经出现的元素,再利用背包的思想来更新集合中的元素即可。 关键点1是要对元素进行取模。 关键点2是要知道暴力dp的重复计算对于解是无用的,所以用set来降重,降重的原理是背包的容量不大,直接维护已经出现了的容量,就不再对没有出现的背包容量进行无效计算了。
void solve(){
int n, m;
cin >> n >> m;
vector<int> a(n);
for (auto& x : a){
cin >> x;
x %= m;
}
set<int> sett;
for (const auto& x : a){
set<int> cur;
for (const auto& it : sett){
cur.insert((it + x) % m);
}
sett.insert(cur.begin(), cur.end());
sett.insert(x);
if (sett.count(0)){
cout << "YES\n";
return;
}
}
cout << "NO\n";
}
标签:set,Modulo,cur,容量,Sum,元素,sett,背包
From: https://www.cnblogs.com/yxcblogs/p/18259904