Description
B 君希望以维护一个长度为
n
的数组,这个数组的下标为从
一共有
- 将 ai 赋值为 cai
- 询问 ∑ri=laimodp
Solution
我们发现这道题有一个地方很不好处理:
caimodp≢caimodpmodp
扩展欧拉定理
ab≡⎧⎩⎨⎪⎪ab%ϕ(p) gcd(a,p)=1ab gcd(a,p)≠1,b<ϕ(p)ab%ϕ(p)+ϕ(p) gcd(a,p)≠1,b≥ϕ(p) (mod p)
根据这个公式一路递推下来,每次 ϕ(ϕ(p)) ,之后最多 log 次变换后 ϕ 值就变为了1,所以超过次数后无需修改.
因此使用线段树统计和,每次暴力修改即可.(注意还要预处理快速幂时间,是快速幂时间复杂度优化成 O(1) )
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 50005;
int n, m, p, c, a[maxn], phi[maxn], k;
int num[30][20005][2];
struct node {
int l, r, cnt;
ll sum;
}t[maxn * 6];
inline ll gi()
{
char c = getchar();
while(c < '0' || c > '9') c = getchar();
ll sum = 0;
while('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
inline ll get_phi(ll x)
{
ll res = x;
for(int i = 2; i * i <= x; ++i)
if(x % i == 0) {
res = res / i * (i - 1);
while(x % i == 0) x /= i;
}
if(x > 1) res = res / x * (x - 1);
return res;
}
inline ll Pow(ll x, ll k, ll mod)
{
ll res = 1;
while(k) {
if(k & 1) res = (res * x) % mod;
x = (x * x) % mod;
k >>= 1;
}
return res;
}
inline ll _pow(ll k, ll t)
{
return (ll)num[t][k / 16384][1] * num[t][k % 16384][0] % phi[t];
}
inline ll gcd(ll a, ll b)
{
if(!b) return a;
return gcd(b, a % b);
}
#define mid ((t[s].l + t[s].r) >> 1)
#define lch (s << 1)
#define rch (s << 1 | 1)
void build(int s, int l, int r)
{
t[s].l = l; t[s].r = r; t[s].cnt = 0;
if(l == r) {t[s].sum = a[l] % phi[0]; return;}
build(lch, l, mid);
build(rch, mid + 1, r);
t[s].sum = (t[s << 1].sum + t[s << 1 | 1].sum) % phi[0];
}
ll query(int s, int l, int r)
{
if(l <= t[s].l && r >= t[s].r) return t[s].sum;
if(r <= mid) return query(lch, l, r);
else if(l > mid) return query(rch, l, r);
else return (query(lch, l, r) + query(rch, l, r)) % phi[0];
}
inline ll modify(int cnt, ll num)
{
ll res = num;
if(res >= phi[cnt]) res = res % phi[cnt] + phi[cnt];
for(int i = cnt; i > 0; --i) {
res = _pow(res, i - 1);
if(gcd(c, res) != 1) res += phi[i - 1];
}
return res % phi[0];
}
void change(int s, int l, int r)
{
if(t[s].cnt >= k) return ;
if(t[s].l == t[s].r) {
++t[s].cnt;
t[s].sum = modify(t[s].cnt, a[t[s].l]);
return;
}
if(r <= mid) change(lch, l, r);
else if(l > mid) change(rch, l, r);
else change(lch, l, r), change(rch, l, r);
t[s].sum = (t[lch].sum + t[rch].sum) % phi[0];
t[s].cnt = min(t[lch].cnt, t[rch].cnt);
}
void prepare()
{
for(int i = 0; i <= k; ++i) {
int tmp = phi[i], j = Pow(c, 16384, phi[i]);
num[i][0][0] = num[i][0][1] = 1;
for(int p = 1; p < 16384; ++p) {
num[i][p][0] = (ll)num[i][p - 1][0] * c % tmp;
num[i][p][1] = (ll)num[i][p - 1][1] * j % tmp;
}
}
}
int main()
{
n = gi(); m = gi(); p = gi(); c = gi();
for(int i = 1; i <= n; ++i) a[i] = gi();
phi[0] = p;
while(p != 1) {
phi[++k] = get_phi(p);
p = phi[k];
}
phi[++k] = 1;
prepare();
build(1, 1, n);
for(int i = 1, opt, l, r; i <= m; ++i) {
opt = gi(); l = gi(); r = gi();
if(!opt) change(1, l, r);
else printf("%lld\n", query(1, l, r));
}
return 0;
}