B. Modulo Sum

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";
}
posted @ 2024-06-21 09:15  _Yxc  阅读(10)  评论(0编辑  收藏  举报