「Ynoi Easy Round 2016」炸脖龙 I

开刷 Ynoi 第一题。

幂次太大,考虑如何减小幂次。

因为不保证 \(p\) 为质数,所以不能用欧拉定理,涉及知识点比较小众,扩展欧拉定理,即

\[a^b \ mod \ p = \begin{cases} & a^{b \ mod \ \varphi(p)} \ ,b < \varphi(p) \\ & a^{b \ mod \ \varphi(p) + \varphi(p)} \ ,b \geq \varphi(p) \end{cases} \]

这样我们就可以通过对指数取模来限制指数大小。

接下来考虑怎么维护,看起来仍然是一坨,但仔细想想,其实不用维护,可以直接暴力,因为对于 \(\forall n \in N^*, n > 2\)\(\varphi(n) \equiv 0 \ (mod \ 2)\),然后又有 \(\varphi(n) \leq \frac{n}{2}, n \equiv 0 \ (mod \ 2)\),所以每上升两阶幂次 \(p\) 至少折半,所以我们可以暴力从左向右扫,若 \(p = 1\) 返回 \(0\) ,即

inline LL f(int l, int r, int p, bool& geq) {
    LL val = BIT.query(l);
    if (p == 1) return geq = true, 0;
    if (val == 1) return geq = false, 1;
    if (l == r) return val >= p ? geq = true : geq = false, val % p;
    return power(val, f(l + 1, r, phi[p], geq) + (geq ? phi[p] : 0), p, geq);
}

注意一些小细节:

  • 判断 \(b \geq \varphi(p)\) 不要用取模后的值判,记录一个 \(geq\) 表示 \(b\) 是否 \(\geq p\) ,动态维护
  • \(a_i = 1\)\((i, r]\) 全部作废,记得清空 \(geq\)
  • 区间加法纯粹凑数,树状数组区加单查不要打错
  • 时刻注意取模,不要爆 \(\text{long long}\)

时间复杂度 \(O(P + N \log P \log N)\)

Code
/*
address:https://www.luogu.com.cn/problem/P3934
AC 2026/7/26 10:17
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 5e5 + 5, P = 2e7 + 5;
int n, q;
bool vis[P];
vector<int> p;
int phi[P];
inline void init() {
    vis[1] = true;
    phi[1] = 1;
    for (int i = 2;i <= P - 4;++i) {
        if (!vis[i]) {
            p.push_back(i);
            phi[i] = i - 1;
        }
        for (int j = 0;i * p[j] <= P - 4;++j) {
            vis[i * p[j]] = true;
            if (i % p[j] > 0) phi[i * p[j]] = phi[i] * (p[j] - 1);
            else {
                phi[i * p[j]] = phi[i] * p[j];
                break;
            }
        }
    }
}
struct BinaryTree {
#define lowbit(x) (x & -x)
    LL c[N];
    inline void change(int x, LL k) { for (;x <= n;x += lowbit(x)) c[x] += k; }
    inline LL query(int x) {
        LL ret = 0;
        for (;x > 0;x -= lowbit(x)) ret += c[x];
        return ret;
    }
}BIT;
inline LL power(LL a, LL k, int mod, bool& geq) {
    bool A = false;
    if (a >= mod) A = true, a %= mod;
    LL ret = 1;
    while (k > 0) {
        if (k & 1)
            if (A || ret * a >= mod) geq = true, ret = ret * a % mod;
            else ret = ret * a;
        if (a * a >= mod) A = true, a = a * a % mod;
        else a = a * a;
        k >>= 1;
    }
    return ret;
}
inline LL f(int l, int r, int p, bool& geq) {
    LL val = BIT.query(l);
    if (p == 1) return geq = true, 0;
    if (val == 1) return geq = false, 1;
    if (l == r) return val >= p ? geq = true : geq = false, val % p;
    return power(val, f(l + 1, r, phi[p], geq) + (geq ? phi[p] : 0), p, geq);
}
int main() {
    init();
    scanf("%d%d", &n, &q);
    for (int i = 1;i <= n;++i) {
        int x;scanf("%d", &x);
        BIT.change(i, x), BIT.change(i + 1, -x);
    }
    while (q--) {
        int op, l, r;scanf("%d%d%d", &op, &l, &r);
        if (op == 1) {
            int x;scanf("%d", &x);
            BIT.change(l, x), BIT.change(r + 1, -x);
        }
        else {
            int p;scanf("%d", &p);
            bool geq = false;
            printf("%lld\n", f(l, r, p, geq));
        }
    }
    return 0;
}
posted @ 2026-07-26 10:45  keysky  阅读(3)  评论(0)    收藏  举报