Address
Solution
前置知识:广义欧拉定理。
当
b
≥
ϕ
(
p
)
b\ge\phi(p)
b≥ϕ(p) 时:
a
b
≡
a
b
 
m
o
d
 
ϕ
(
p
)
+
ϕ
(
p
)
(
 
m
o
d
 
p
)
a^b\equiv a^{b\bmod\phi(p)+\phi(p)}(\bmod p)
ab≡abmodϕ(p)+ϕ(p)(modp)
而题目中的修改:
c
c
c
.
.
.
a
i
c^{c^{c^{...^{a_i}}}}
ccc...ai
实际上是:
c
c
c
.
.
.
a
i
 
m
o
d
 
ϕ
(
p
)
+
ϕ
(
p
)
=
c
c
c
.
.
.
a
i
 
m
o
d
 
ϕ
(
ϕ
(
p
)
)
+
ϕ
(
ϕ
(
p
)
)
 
m
o
d
 
ϕ
(
p
)
+
ϕ
(
p
)
c^{c^{c^{...^{a_i}}}\bmod\phi(p)+\phi(p)}=c^{c^{c^{...^{a_i}}\bmod\phi(\phi(p))+\phi(\phi(p))}\bmod\phi(p)+\phi(p)}
ccc...aimodϕ(p)+ϕ(p)=ccc...aimodϕ(ϕ(p))+ϕ(ϕ(p))modϕ(p)+ϕ(p)
由于
p
p
p 不断地变成
ϕ
(
p
)
\phi(p)
ϕ(p) 之多
O
(
log
p
)
O(\log p)
O(logp) 次后会变成
1
1
1 ,
所以一个位置最多被修改
O
(
log
p
)
O(\log p)
O(logp) 之后就不会变。
所以,我们用线段树维护区间和以及区间内所有位置被修改的最少次数,
修改时遍历到叶子节点,如果遍历到一个节点,这个节点被修改的次数达到了上限,就 return 掉。
这样,每个叶子节点到根的路径最多被修改
O
(
log
p
)
O(\log p)
O(logp) 次。
我们需要对于每个
a
i
a_i
ai 和
j
j
j ,预处理出:
F
(
p
,
a
i
,
j
)
=
c
c
c
.
.
.
a
i
 
m
o
d
 
p
F(p,a_i,j)=c^{c^{c^{...^{a_i}}}}\bmod p
F(p,ai,j)=ccc...aimodp
(共
j
j
j 个
c
c
c )
根据广义欧拉定理,上式等于:
c
F
(
ϕ
(
p
)
,
a
i
,
j
−
1
)
+
ϕ
(
p
)
c^{F(\phi(p),a_i,j-1)+\phi(p)}
cF(ϕ(p),ai,j−1)+ϕ(p)
递归求解。
注意两个细节:
(1)
c
c
c 的幂。注意到指数最多只有
2
×
1
0
8
2\times10^8
2×108 ,所以可以预处理出
c
0
c^0
c0 ,
c
1
c^1
c1 ,一直到
c
2
×
1
0
4
−
1
c^{2\times 10^4-1}
c2×104−1 的值,然后再处理
c
2
×
1
0
4
c^{2\times 10^4}
c2×104 ,
(
c
2
×
1
0
4
)
2
(c^{2\times 10^4})^2
(c2×104)2 ,
(
c
2
×
1
0
4
)
3
(c^{2\times 10^4})^3
(c2×104)3 , …… 的值,则:
c
x
=
(
c
2
×
1
0
4
)
⌊
x
2
×
1
0
4
⌋
×
c
x
 
m
o
d
 
(
2
×
1
0
4
)
c^x=(c^{2\times 10^4})^{\lfloor\frac{x}{2\times10^4}\rfloor}\times c^{x\bmod (2\times10^4)}
cx=(c2×104)⌊2×104x⌋×cxmod(2×104)
(2)注意当指数小于
ϕ
(
p
)
\phi(p)
ϕ(p) 则降幂时不能加上
ϕ
(
p
)
\phi(p)
ϕ(p) 。
复杂度
O
(
n
(
log
n
log
p
+
log
2
p
)
)
O(n(\log n\log p+\log^2p))
O(n(lognlogp+log2p)) 。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define p2 p << 1
#define p3 p << 1 | 1
using namespace std;
inline int read()
{
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
template <class T>
void Swap(T &a, T &b) {a ^= b; b ^= a; a ^= b;}
template <class T>
T Min(T a, T b) {return a < b ? a : b;}
const int N = 5e4 + 5, M = N << 2, E = 104, ORZ = 2e4, L = 2e4 + 5;
int n, m, ZZQ, c, a[N], tot, PYZ[N], p[N], q[N], sum[M], cnt[M],
f[N][E], g[E][L], h[E][L];
bool ig[E][L], ih[E][L], Flag;
int phi(int n)
{
int i, j, S = sqrt(n), tot = 0, res = 1;
For (i, 2, S)
{
if (n % i) continue;
p[++tot] = i; q[tot] = 0;
while (n % i == 0) q[tot]++, n /= i;
}
if (n > 1) p[++tot] = n, q[tot] = 1;
For (i, 1, tot)
{
res *= p[i] - 1;
For (j, 1, q[i] - 1) res *= p[i];
}
return res;
}
int powx(int x, int p)
{
return 1ll * h[x][p / ORZ] * g[x][p % ORZ] % PYZ[x];
}
bool chk(int x, int p)
{
return ih[x][p / ORZ] || ig[x][p % ORZ]
|| 1ll * h[x][p / ORZ] * g[x][p % ORZ] >= PYZ[x];
}
int F(int x, int a, int p)
{
if (!x) return Flag = p || a, 0;
if (!p) return Flag = a >= PYZ[x], a % PYZ[x];
int tmp = F(x - 1, a, p - 1), res;
if (Flag) res = powx(x, tmp + PYZ[x - 1]);
else res = powx(x, tmp);
return Flag = c == 1 ? PYZ[x] == 1 :
Flag || chk(x, tmp), res;
}
void build(int l, int r, int p)
{
if (l == r) return (void) (sum[p] = a[l]);
int mid = l + r >> 1;
build(l, mid, p2); build(mid + 1, r, p3);
sum[p] = (sum[p2] + sum[p3]) % ZZQ;
}
void upt(int p)
{
sum[p] = (sum[p2] + sum[p3]) % ZZQ;
cnt[p] = Min(cnt[p2], cnt[p3]);
}
void change(int l, int r, int s, int e, int p)
{
if (cnt[p] >= tot + 2) return;
if (l == r) return (void) (sum[p] = f[l][++cnt[p]]);
int mid = l + r >> 1;
if (e <= mid) change(l, mid, s, e, p2);
else if (s >= mid + 1) change(mid + 1, r, s, e, p3);
else change(l, mid, s, mid, p2),
change(mid + 1, r, mid + 1, e, p3);
upt(p);
}
int ask(int l, int r, int s, int e, int p)
{
if (l == s && r == e) return sum[p];
int mid = l + r >> 1;
if (e <= mid) return ask(l, mid, s, e, p2);
else if (s >= mid + 1) return ask(mid + 1, r, s, e, p3);
else return (ask(l, mid, s, mid, p2)
+ ask(mid + 1, r, mid + 1, e, p3)) % ZZQ;
}
int main()
{
int i, j, p, op, l, r;
n = read(); m = read(); p = ZZQ = read(); c = read();
For (i, 1, n) a[i] = read();
PYZ[tot = 0] = ZZQ;
while (p > 1) p = PYZ[++tot] = phi(p);
For (i, 0, tot >> 1)
if (i != tot - i) Swap(PYZ[i], PYZ[tot - i]);
For (i, 0, tot)
{
g[i][0] = h[i][0] = 1 % PYZ[i];
ig[i][0] = ih[i][0] = PYZ[i] == 1;
For (j, 1, ORZ)
g[i][j] = 1ll * g[i][j - 1] * c % PYZ[i],
ig[i][j] = ig[i][j - 1] || 1ll * g[i][j - 1] * c >= PYZ[i];
For (j, 1, ORZ)
h[i][j] = 1ll * h[i][j - 1] * g[i][ORZ] % PYZ[i],
ih[i][j] = ih[i][j - 1] || ig[i][ORZ] ||
1ll * h[i][j - 1] * g[i][ORZ] >= PYZ[i];
}
For (i, 1, n) For (j, 0, tot + 2)
f[i][j] = F(tot, a[i], j);
build(1, n, 1);
while (m--)
{
op = read(); l = read(); r = read();
if (op == 0) change(1, n, l, r, 1);
else printf("%d\n", ask(1, n, l, r, 1));
}
return 0;
}