Description
Informatikverbindetdichundmich.
信息将你我连结。B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数。一共有m个操作,可以分为两种:0 l r表示将第l个到第r个数(al,al+1,...,ar)中的每一个数ai替换为c^ai,即c的ai次方,其中c是输入的一个常数,也就是执行赋值ai=c^ai1 l r求第l个到第r个数的和,也就是输出:sigma(ai),l<=i<=rai因为这个结果可能会很大,所以你只需要输出结果mod p的值即可。
Input
第一行有三个整数n,m,p,c,所有整数含义见问题描述。
接下来一行n个整数,表示a数组的初始值。
接下来m行,每行三个整数,其中第一个整数表示了操作的类型。
如果是0的话,表示这是一个修改操作,操作的参数为l,r。
如果是1的话,表示这是一个询问操作,操作的参数为l,r。
1 ≤ n ≤ 50000, 1 ≤ m ≤ 50000, 1 ≤ p ≤ 100000000, 0 < c <p, 0 ≤ ai < p
Output
对于每个询问操作,输出一行,包括一个整数表示答案mod p的值。
Sample Input
4 4 7 2
1 2 3 4
0 1 4
1 2 4
0 1 4
1 1 3
1 2 3 4
0 1 4
1 2 4
0 1 4
1 1 3
Sample Output
0
3
3
HINT
鸣谢多名网友提供正确数据,已重测!
正解:扩展欧拉定理+线段树。
扩展欧拉定理:$a^{b} \ mod p=a^{b \ mod \varphi(p)+\varphi(p)}$,如果$b<\varphi(p)$则不加$\varphi(p)$。
因为一个数取$log$次$\varphi$就会变成$1$,于是我们可以发现,一个数变换$log$次以后就不会变了。
于是用线段树记录每个数变换的次数,每次单点修改时直接用$\varphi$从后往前递推。
因为每次要快速幂,所以复杂度是$O(nlog^{3}n)$的,我们预处理$c^{x}$和$c^{20000x}$就能$O(1)$算出幂了。
1 #include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ll long long 5 #define ls (x<<1) 6 #define rs (x<<1|1) 7 #define N (100005) 8 9 using namespace std; 10 11 int sum[N<<2],tag[N<<2],a[N],phi[105],qp[105][20005],qw[105][20005],n,m,c,tot,base=20000; 12 13 il int gi(){ 14 RG int x=0,q=1; RG char ch=getchar(); 15 while ((ch<‘0‘ || ch>‘9‘) && ch!=‘-‘) ch=getchar(); 16 if (ch==‘-‘) q=-1,ch=getchar(); 17 while (ch>=‘0‘ && ch<=‘9‘) x=x*10+ch-48,ch=getchar(); 18 return q*x; 19 } 20 21 il int mul(RG int a,RG int b,RG int rhl){ 22 return 1LL*a*b>=rhl ? 1LL*a*b%rhl+rhl : a*b; 23 } 24 25 il int get_phi(RG int x){ 26 RG int res=x; 27 for (RG int i=2;i*i<=x;++i){ 28 if (x%i) continue; 29 while (!(x%i)) x/=i; 30 res=res/i*(i-1); 31 } 32 if (x!=1) res=res/x*(x-1); return res; 33 } 34 35 il void pre(){ 36 while (phi[tot]!=1) ++tot,phi[tot]=get_phi(phi[tot-1]); phi[++tot]=1; 37 for (RG int i=0;i<=tot;++i){ 38 qp[i][0]=qw[i][0]=mul(1,1,phi[i]); 39 for (RG int j=1;j<=base;++j) 40 qp[i][j]=mul(qp[i][j-1],c,phi[i]); 41 for (RG int j=1;j<=base;++j) 42 qw[i][j]=mul(qw[i][j-1],qp[i][base],phi[i]); 43 } 44 return; 45 } 46 47 il int trans(RG int x,RG int k){ 48 while (k) --k,x=mul(qw[k][x/base],qp[k][x%base],phi[k]); 49 return x>=phi[0] ? x-phi[0] : x; 50 } 51 52 il void pushup(RG int x){ 53 sum[x]=sum[ls]+sum[rs]; if (sum[x]>=phi[0]) sum[x]-=phi[0]; 54 tag[x]=min(tag[ls],tag[rs]); return; 55 } 56 57 il void build(RG int x,RG int l,RG int r){ 58 if (l==r){ sum[x]=(a[l]=gi())%phi[0]; return; } RG int mid=(l+r)>>1; 59 build(ls,l,mid),build(rs,mid+1,r),pushup(x); return; 60 } 61 62 il void update(RG int x,RG int l,RG int r,RG int xl,RG int xr){ 63 if (tag[x]>=tot) return; 64 if (l==r){ ++tag[x],sum[x]=trans(a[l],tag[x]); return; } 65 RG int mid=(l+r)>>1; 66 if (xr<=mid) update(ls,l,mid,xl,xr); 67 else if (xl>mid) update(rs,mid+1,r,xl,xr); 68 else update(ls,l,mid,xl,mid),update(rs,mid+1,r,mid+1,xr); 69 pushup(x); return; 70 } 71 72 il int query(RG int x,RG int l,RG int r,RG int xl,RG int xr){ 73 if (xl<=l && r<=xr) return sum[x]; RG int mid=(l+r)>>1; 74 if (xr<=mid) return query(ls,l,mid,xl,xr); 75 if (xl>mid) return query(rs,mid+1,r,xl,xr); 76 RG int res=query(ls,l,mid,xl,mid); 77 res+=query(rs,mid+1,r,mid+1,xr); 78 if (res>=phi[0]) res-=phi[0]; return res; 79 } 80 81 int main(){ 82 #ifndef ONLINE_JUDGE 83 freopen("meet.in","r",stdin); 84 freopen("meet.out","w",stdout); 85 #endif 86 n=gi(),m=gi(),phi[0]=gi(),c=gi(),pre(),build(1,1,n); 87 while (m--){ 88 RG int op=gi(),l=gi(),r=gi(); 89 if (op) printf("%d\n",query(1,1,n,l,r)%phi[0]); 90 else update(1,1,n,l,r); 91 } 92 return 0; 93 }