Description
给定序列 a = ( a 1 , a 2 , ⋯ , a n ) a=(a_1,a_2,\cdots,a_n) a=(a1,a2,⋯,an).
有 m m m 个操作,分以下两种:
- modify ( l , r , k ) \operatorname{modify}(l,r,k) modify(l,r,k):对每个 i ∈ [ l , r ] i \in [l,r] i∈[l,r] 执行 a i ← a i + k a_i \leftarrow a_i+k ai←ai+k
- query ( l , r , p ) \operatorname{query}(l,r,p) query(l,r,p):定义 f ( l , l ) = a l f(l,l)=a_l f(l,l)=al, f ( l , r ) = a l f ( l + 1 , r ) ( l < r ) f(l,r)=a_l^{f(l+1,r)} \;(l < r) f(l,r)=alf(l+1,r)(l<r),求 f ( l , r ) m o d p f(l,r) \bmod p f(l,r)modp。
Limitations
1
≤
n
,
m
≤
5
×
1
0
5
1 \le n,m \le 5\times 10^5
1≤n,m≤5×105
1
≤
a
i
≤
2
×
1
0
9
1 \le a_i \le 2\times 10^9
1≤ai≤2×109
1
≤
p
≤
2
×
1
0
7
1 \le p \le 2\times 10^7
1≤p≤2×107
0
≤
k
≤
2
×
1
0
9
0 \le k \le 2\times 10^9
0≤k≤2×109
2.5
s
,
512
MB
2.5\text{s},512\text{MB}
2.5s,512MB
Solution
连幂运算不满足结合律,不能线段树维护。
考虑扩展欧拉定理:
a
b
≡
a
b
m
o
d
ϕ
(
p
)
+
ϕ
(
p
)
×
[
b
≥
ϕ
(
p
)
]
(
m
o
d
p
)
a^b \equiv a^{b \bmod \phi(p)+\phi(p)\times[b \ge \phi(p)]} \pmod p
ab≡abmodϕ(p)+ϕ(p)×[b≥ϕ(p)](modp)
我们直接暴力 dfs
遍历每个数求值,由于每个
p
p
p 最多递归
log
p
\log p
logp 层,因此不会超时。
但是,如何判断
[
b
≥
ϕ
(
p
)
]
[b \ge \phi(p)]
[b≥ϕ(p)]?其实不难,跑快速幂时判断一下即可。
然后考虑边界情况:
- p = 1 p=1 p=1 时,答案一定为 0 0 0
- a l = 1 a_l=1 al=1 时,答案一定为 1 1 1
a a a 用树状数组维护,再筛一下 ϕ ( p ) \phi(p) ϕ(p) 即可。
Code
3.58 KB , 3.1 s , 95.71 MB (in total, C++ 20 with O2) 3.58\text{KB},3.1\text{s},95.71\text{MB}\;\texttt{(in total, C++ 20 with O2) } 3.58KB,3.1s,95.71MB(in total, C++ 20 with O2)
// Problem: P3934 [Ynoi2016] 炸脖龙 I
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3934
// Memory Limit: 512 MB
// Time Limit: 2500 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;
template<class T>
bool chmax(T &a, const T &b){
if(a < b){ a = b; return true; }
return false;
}
template<class T>
bool chmin(T &a, const T &b){
if(a > b){ a = b; return true; }
return false;
}
int lowbit(int x){
return x & -x;
}
template<class T>
struct fenwick{
int n;
vector<T> c;
fenwick() {}
fenwick(int _n): n(_n){
c.resize(n + 1);
}
fenwick(const vector<T> &a): n(a.size()){
c.resize(n + 1);
for(int i = 1; i <= n; i++){
c[i] = c[i] + a[i - 1];
int j = i + lowbit(i);
if(j <= n) c[j] = c[j] + c[i];
}
}
void add(int x, const T& v){
for(int i = x + 1; i <= n; i += lowbit(i)) c[i] = c[i] + v;
}
T ask(int x){
T ans{};
for(int i = x + 1; i; i -= lowbit(i)) ans = ans + c[i];
return ans;
}
T ask(int l, int r){
return ask(r) - ask(l - 1);
}
};
using Node = pair<i64, bool>;
Node power(i64 a, i64 b, i64 p) {
Node res(1, false);
i64 t = a % p;
if (a >= p) {
res.second = true;
res.first %= p;
}
while (b) {
if (b & 1) {
res.first *= t;
}
if (res.first >= p) {
res.second = true;
res.first %= p;
}
t *= t;
if ((b / 2) && t >= p) {
res.second = true;
t %= p;
}
b >>= 1;
}
return res;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, m;
scanf("%d %d", &n, &m);
vector<i64> a(n);
fenwick<i64> bit(n);
for (int i = 0; i < n; i++) {
scanf("%lld", &a[i]);
bit.add(i, a[i] - (i > 0 ? a[i - 1] : 0LL));
}
vector<bool> np;
vector<int> pri, phi;
auto sieve = [&](int n) {
np.resize(n + 1, false);
phi.resize(n + 1, 0);
phi[1] = 1;
for (int i = 2; i <= n; i++) {
if (!np[i]) {
pri.push_back(i);
phi[i] = i - 1;
}
for (int j = 0; j < pri.size() && 1LL * i * pri[j] <= n; j++) {
np[i * pri[j]] = true;
if (i % pri[j] == 0) {
phi[i * pri[j]] = phi[i] * pri[j];
break;
}
phi[i * pri[j]] = phi[i] * (pri[j] - 1);
}
}
};
sieve(2e7);
auto solve = [&](auto &&self, int l, int r, i64 p) -> Node {
i64 t = bit.ask(l);
if (p == 1) {
return Node(0, true);
}
if (l == r) {
return Node(t % p, t >= p);
}
if (t == 1) {
return Node(1, false);
}
Node mid = self(self, l + 1, r, phi[p]);
if (mid.second) {
mid.first += phi[p];
}
return power(t, mid.first, p);
};
for (int i = 0; i < m; i++) {
int op, l, r;
i64 p;
scanf("%d %d %d %lld", &op, &l, &r, &p);
l--, r--;
if (op == 1) {
bit.add(l, p);
bit.add(r + 1, -p);
}
else {
i64 res = solve(solve, l, r, p).first;
printf("%lld\n", (res % p + p) % p);
}
}
return 0;
}