「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;
}

浙公网安备 33010602011771号