【题解】P10045 [CCPC 2023 北京市赛] 线段树

这我哪会啊

因为 \(a_i\) 时刻为奇数,所以考虑把 \(a_i\) 表示成 \(2b_i+1\) 的形式。此时区间 \([l,r]\) 的乘积即可以表示为 \(\prod\limits_{i=l}^r(2b_i+1)\) 的形式。又因为答案是对 \(2^{20}\) 取模的,且有 \(2\mid 2b_i\),因此上面的这个式子只用考虑有最多 \(19\) 个选 \(2b_i\) 的情况。

考虑直接用线段树维护这个东西。记 \(cnt_i\) 表示在当前线段树结点对应区间 \([l,r]\) 上选 \(i\)\(2b_i\) 作为乘积的方案数。合并枚举左右两侧选择的 \(2b_i\) 数量然后简单计算即可。根据上面的分析只需要维护 \(i=0\ldots 19\) 时的 \(cnt_i\) 值即可。

总时间复杂度为 \(O(nk^2\log n)\),其中 \(k\)\(20\),卡常后可以过。

一个卡常技巧是答案用 unsigned int 存,众所周知 unsigned int 的乘法取模比 int 快,而且这个东西对 \(2^{32}\) 自然溢出,然后就可以卡着时间限制通过。谴责出题人卡常。

// #pragma GCC optimize(3, "Ofast", "inline", "unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
// #define int long long

using namespace std;
const int N = 200010;
const int mod = 1048576;
const int inf = 1e18;

#define int ui

using ui = unsigned;
using ld = long double;
using ull = unsigned long long;
using i128 = __int128;
const ull base = 13331;

namespace Luminescent
{
    const double pi = acos(-1);
    const ld pi_l = acosl(-1);
    struct DSU
    {
        int fa[N], siz[N];
        inline DSU() { iota(fa, fa + N, 0), fill(siz, siz + N, 1); }
        inline void init(int maxn) { iota(fa, fa + maxn + 1, 0), fill(siz, siz + maxn + 1, 1); }
        inline int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
        inline int merge(int x, int y)
        {
            x = find(x), y = find(y);
            if (siz[x] > siz[y])
                x ^= y ^= x ^= y;
            if (x != y)
                return fa[x] = y, siz[y] += siz[x], 1;
            return 0;
        }
    };
    inline void add(int &x, int a) { x = (x + a) % mod; }
    inline void sub(int &x, int a) { x = (x - a + mod) % mod; }
    inline int power(int a, int b, int c)
    {
        int sum = 1;
        while (b)
        {
            if (b & 1)
                sum = 1ll * sum * a % c;
            a = 1ll * a * a % c, b >>= 1;
        }
        return sum;
    }
    inline int inversion(int x) { return power(x, mod - 2, mod); }
    inline int inversion(int x, int mod) { return power(x, mod - 2, mod); }
    inline int varphi(int x)
    {
        int phi = 1;
        for (int i = 2; i * i <= x; ++i)
            if (x % i == 0)
            {
                phi *= (i - 1);
                x /= i;
                while (x % i == 0)
                    phi *= i, x /= i;
            }
        if (x > 1)
            phi *= (x - 1);
        return phi;
    }
}
using namespace Luminescent;

namespace Loyalty
{
    int C[N][22];
    int a[N], pwr[mod][20];
    struct Node
    {
        int l, r, cnt[20], tag;
        inline void init(int p)
        {
            l = r = p, tag = 0, memset(cnt, 0, sizeof cnt);
            cnt[0] = 1, cnt[1] = a[p];
        }
        inline void push(int x)
        {
            tag = (tag + x) % mod;
            int tmp[20] = {0};
            for (int i = 0; i < 20; ++i)
                for (int j = 0; j <= min(i, r - l + 1); ++j)
                    tmp[i] = (tmp[i] + cnt[j] * pwr[x][i - j] % mod * C[r - l + 1 - j][i - j]) % mod;
            for (int i = 0; i < 20; ++i)
                cnt[i] = tmp[i];
        }
    } tree[N << 2];
    inline Node operator+(const Node &l, const Node &r)
    {
        Node res;
        res.l = l.l, res.r = r.r, res.tag = 0;
        memset(res.cnt, 0, sizeof res.cnt);
        for (int i = 0; i < 20; ++i)
            for (int j = 0; i + j < 20; ++j)
                res.cnt[i + j] = (res.cnt[i + j] + l.cnt[i] * r.cnt[j] % mod) % mod;
        return res;
    }
    inline void build(int l, int r, int rt)
    {
        if (l == r)
            return tree[rt].init(l);
        int mid = l + r >> 1;
        build(l, mid, rt << 1), build(mid + 1, r, rt << 1 | 1);
        tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
    }
    inline void pushdown(int rt)
    {
        if (tree[rt].tag)
        {
            tree[rt << 1].push(tree[rt].tag);
            tree[rt << 1 | 1].push(tree[rt].tag);
            tree[rt].tag = 0;
        }
    }
    inline void loyalty(int rt, int ll, int rr, int v)
    {
        int &l = tree[rt].l, &r = tree[rt].r;
        if (ll <= l && r <= rr)
            return tree[rt].push(v);
        int mid = l + r >> 1;
        pushdown(rt);
        if (ll <= mid)
            loyalty(rt << 1, ll, rr, v);
        if (mid < rr)
            loyalty(rt << 1 | 1, ll, rr, v);
        tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
    }
    inline Node luminescent(int rt, int ll, int rr)
    {
        int &l = tree[rt].l, &r = tree[rt].r;
        if (ll <= l && r <= rr)
            return tree[rt];
        int mid = l + r >> 1;
        pushdown(rt);
        if (ll <= mid && mid < rr)
            return luminescent(rt << 1, ll, rr) + luminescent(rt << 1 | 1, ll, rr);
        if (ll <= mid)
            return luminescent(rt << 1, ll, rr);
        return luminescent(rt << 1 | 1, ll, rr);
    }
    inline void init() { }
    inline void main([[maybe_unused]] int _ca, [[maybe_unused]] int atc)
    {
        int n, q; cin >> n >> q;
        for (int i = 1; i <= n; ++i)
            cin >> a[i], --a[i];
        build(1, n, 1);
        for (int i = 0; i < mod; ++i)
        {
            pwr[i][0] = 1;
            for (int j = 1; j < 20; ++j)
                pwr[i][j] = pwr[i][j - 1] * i % mod;
        }
        for (int i = 0; i < N; ++i)
        {
            C[i][0] = 1;
            for (int j = 1; j <= min(i, 20u); ++j)
                C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
        }
        while (q--)
        {
            int o, l, r, x; cin >> o >> l >> r;
            if (o == 1) { cin >> x; loyalty(1, l, r, x); }
            else
            {
                auto o = luminescent(1, l, r);
                int res = 0;
                for (int i = 0; i < 20; ++i)
                    res = (res + o.cnt[i]) % mod;
                cout << res << '\n';
            }
        }
    }
}

signed main()
{
    cin.tie(0)->sync_with_stdio(false);
    cout << fixed << setprecision(15);
    int T = 1;
    // cin >> T;
    Loyalty::init();
    for (int ca = 1; ca <= T; ++ca)
        Loyalty::main(ca, T);
    return 0;
}

posted @ 2026-01-31 19:04  0103abc  阅读(4)  评论(0)    收藏  举报