Codeforces 1114F(欧拉函数、线段树)

AC通道

要点

  • 欧拉函数对于素数有一些性质,考虑将输入数据唯一分解后进行素数下的处理。
  • 对于素数\(p\)有:\(\phi(p^k)=p^{k-1}*(p-1)=p^k*\frac{p-1}{p}\),因此将\(a_i\)唯一分解后有:\(\phi(\prod_{i=l}^ra_i)=\prod_{i=l}^ra_i*\prod_{p\ \in P}\frac{p-1}{p}\),其中\(P\)\([l,r]\)内的\(a_i\)分解后的素数集合。
  • 这样转化公式以后,就只需线段树维护一下区间乘积和区间是否有某素数即可,第二个维护可以使用bitset二进制串代表有没有。
  • \(a_i\)\(x\)都很小,可以预处理1~300范围内的所需数据。
const int maxn = 4e5 + 5, mod = 1e9 + 7;
int n, q;
bst Mask[305];//bitset
vector<int> primes, invp;

int ksm(int a, int b) {
    int res = 1;
    for (; b; b >>= 1) {
        if (b & 1)  res = (ll)res * a % mod;
        a = (ll)a * a % mod;
    }
    return res;
}

void pre(int n) {
    bool vis[305] = {false};
    for (int i = 2; i <= n; i++) {
        if (!vis[i]) {
            primes.push_back(i);
            invp.push_back(ksm(i, mod - 2));
            for (int j = i * i; j <= n; j += i) {
                vis[j] = true;
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < primes.size(); j++) {
            if (i % primes[j] == 0) {
                Mask[i][j] = 1;
            }
        }
    }
}

class SegmentTree {
public:
    #define ls(p) p << 1
    #define rs(p) p << 1 | 1
    
    struct Node {
        int l, r, mul, tag;
        bst bits, laz;
    }t[maxn * 3];

    void Push_up(int p) {
        t[p].mul = (ll)t[ls(p)].mul * t[rs(p)].mul % mod;
        t[p].bits = t[ls(p)].bits | t[rs(p)].bits;
        t[p].tag = 1;
        t[p].laz.reset();
    }

    void Deal(int son, int fa) {
        t[son].mul = (ll)t[son].mul * ksm(t[fa].tag, t[son].r - t[son].l + 1) % mod;
        t[son].bits |= t[fa].laz;
        t[son].tag = (ll)t[son].tag * t[fa].tag % mod;
        t[son].laz |= t[fa].laz;
    }

    void Push_down(int p) {
        if (t[p].tag != 1 || t[p].laz.any()) {
            Deal(ls(p), p), Deal(rs(p), p);
            t[p].tag = 1, t[p].laz.reset();
        }
    }

    void Build(int l, int r, int p) {
        t[p].l = l, t[p].r = r;
        if (l == r) {
            cin >> t[p].mul;
            t[p].tag = 1;
            t[p].bits = Mask[t[p].mul];
            t[p].laz.reset();
            return;
        }
        int mid = (l + r) >> 1;
        Build(l, mid, ls(p));
        Build(mid + 1, r, rs(p));
        Push_up(p);
    }

    void Modify(int l, int r, int p, int x) {
        if (l <= t[p].l && t[p].r <= r) {
            t[p].mul = (ll)t[p].mul * ksm(x, t[p].r - t[p].l + 1) % mod;
            t[p].tag = (ll)t[p].tag * x % mod;
            t[p].bits |= Mask[x];
            t[p].laz |= Mask[x];
            return;
        }
        Push_down(p);
        int mid = (t[p].l + t[p].r) >> 1;
        if (l <= mid)   Modify(l, r, ls(p), x);
        if (mid < r)    Modify(l, r, rs(p), x);
        Push_up(p);
    }
    
    friend Node operator + (const Node &A, const Node &B) {
        Node tmp;
        tmp.mul = (ll)A.mul * B.mul % mod;
        tmp.bits = A.bits | B.bits;
        return tmp;
    }

    Node Query(int l, int r, int p) {
        if (l <= t[p].l && t[p].r <= r)
            return t[p];
        Push_down(p);
        int mid = (t[p].l + t[p].r) >> 1;
        if (mid >= r)   return Query(l, r, ls(p));
        if (l > mid)    return Query(l, r, rs(p));
        return Query(l, r, ls(p)) + Query(l, r, rs(p));
    }
}T;

int main() {
    ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);

    pre(300);
    cin >> n >> q;
    T.Build(1, n, 1);
    while (q--) {
        string s;
        int l, r, x;
        cin >> s >> l >> r;

        if (s == "MULTIPLY") {
            cin >> x;
            T.Modify(l, r, 1, x);
        } else {
            auto res = T.Query(l, r, 1);
            int ans = res.mul;
            for (int j = 0; j < primes.size(); j++) {
                if (res.bits[j]) {
                    ans = (ll)ans * (primes[j] - 1) % mod * invp[j] % mod;
                }
            }
            cout << ans << '\n';
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/AlphaWA/p/10716317.html