• P8193 [USACO22FEB] 高维前缀和


    题意

    传送门 P8193 [USACO22FEB] Sleeping in Class P

    题解

    s = ∑ a i s = \sum a_i s=ai p r e s u m i = ∑ j ≤ i a j presum_i = \sum_{j\leq i}a_j presumi=jiaj。对于第 i i i 个询问,存在满足条件操作的充要条件是 q i ∣ s q_i\vert s qis。令 x = ∑ [ p r e s u m i m o d    q i = 0 ] x = \sum [presum_i \mod q_i = 0] x=[presumimodqi=0]。 至少需要合并的次数为 n − x n-x nx,至少需要分裂的次数为 s / q i − x s/q_i-x s/qix,且这样的操作可以满足条件。答案为 n + s / q i − 2 x n + s/q_i -2x n+s/qi2x

    q i q_i qi s s s 的因数,则对有所有前缀和,只需考虑它们与 s s s 的公因子。将所有数字按照算数基本定理进行分解,则问题转化为求 q i q_i qi 对应的高维前缀和。高维前缀和可参考 Some SOS DP Insights

    大数分解可以使用 Pollard-Rho 算法。另一种做法是只筛 [ 1 , 1 0 6 ] [1,10^6] [1,106] 的质因子,若最后得到的数 n ≤ 1 0 12 n\leq 10^{12} n1012 ,由于合数存在小于等于 n \sqrt{n} n 的因子,故 n n n 是质数,质因数分解完毕,直接算高维前缀和即可。若 n > 1 0 12 n>10^{12} n>1012,则存在两个大于 1 0 12 10^{12} 1012 的质数,则总的质因子数上界为 m a x 1 ≤ i ≤ 1 0 6 d ( i ) × 2 2 max_{1\leq i\leq 10^6}d(i) \times 2^2 max1i106d(i)×22,其中 d ( i ) d(i) d(i) 代表 i i i 的因数数量,实际上数量较小,可以直接暴力算 x x x,记忆化优化即可。

    #include 
    using namespace std;
    using ll = long long;
    
    ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
    
        int n;
        cin >> n;
        vector<ll> a(n);
        for (int i = 0; i < n; ++i) {
            cin >> a[i];
        }
        for (int i = 0; i + 1 < n; ++i) {
            a[i + 1] += a[i];
        }
        ll s = a[n - 1];
    
        for (int i = 0; i < n; ++i) {
            a[i] = gcd(a[i], s);
        }
    
        map<ll, int> prime;
        bool bf = 0;
        {
            ll x = s;
            for (int i = 2; i <= 1e6; ++i) {
                while (x % i == 0) {
                    prime[i] += 1;
                    x /= i;
                }
            }
    
            if (x > 1) {
                if (x > 1e12) {
                    bf = 1;
                } else {
                    prime[x] += 1;
                }
            }
        }
    
        vector<int> dim;
        for (auto [x, c] : prime) {
            dim.push_back(c + 1);
        }
        int m = dim.size();
        vector<int> bs(m + 1);
        bs[0] = 1;
        for (int i = 0; i < m; ++i) {
            bs[i + 1] = bs[i] * dim[i];
        }
    
        auto get = [&](ll x) {
            vector<int> c;
            for (auto [p, _] : prime) {
                int t = 0;
                while (x % p == 0) {
                    ++t;
                    x /= p;
                }
                c.push_back(t);
            }
    
            int res = 0;
            for (int i = 0; i < m; ++i) {
                res += c[i] * bs[i];
            }
            return res;
        };
    
        vector<int> sum(bs[m]);
        for (auto x : a) {
            sum[get(x)] += 1;
        }
        for (int i = 0; i < m; ++i) {
            for (int j = bs[m] - 1; j >= 0; --j) {
                if (j / bs[i] % dim[i] == dim[i] - 1) continue;
                sum[j] += sum[j + bs[i]];
            }
        }
    
        int q;
        cin >> q;
        map<ll,ll> mem;
        while (q--) {
            ll b;
            cin >> b;
            if (s % b > 0) {
                cout << "-1\n";
                continue;
            }
            if (bf) {
                if (mem.count(b) == 0) {
                    int x = 0;
                    for (int i = 0; i < n; ++i) {
                        x += a[i] % b == 0;
                    }
                    mem[b] = s / b + n - 2 * x;
                }
                cout << mem[b] << '\n';
            } else {
                ll res = s / b + n - sum[get(b)] * 2;
                cout << res << '\n';
            }
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
  • 相关阅读:
    数组——二分查找
    简单动态字符串SDS
    【kali】一款黑客们都在使用的操作系统
    Python轻量级Web框架:Bottle库
    如何通过EasyCVR接口监测日志观察平台拉流情况?
    Nginx虚拟主机的搭建 基于ip 基于端口 基于域名
    C++ | Leetcode C++题解之第42题接雨水
    java毕业设计基于javaweb+mysql数据库实现的校园迎新(新生报道)网站含论文+开题报告
    14天学习训练营导师课程-Pygame学习笔记-Part1(环境准备)
    操作系统·操作系统引论
  • 原文地址:https://blog.csdn.net/neweryyy/article/details/127433349