[SHOI2017]相逢是问候
Description
信息将你我连结。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
扩展欧拉定理:
$a^{b} \ mod p=a^{b \ mod \varphi(p)+\varphi(p)}$,如果$b<\varphi(p)$则不加$\varphi(p)$。
因为一个数取cnt=log次Φ变换就会变成1,一个数变换log次以后就不会变了。
所以用线段树维护一个点的变换次数k
区间修改要修改到每个点,只要判断大于变换次数大于cnt时不换(换了也一样)
根据分析,复杂度最多nlogn
然后直接从cnt往1一步一步模拟变换算出结果,然后快速幂,计算过程O(logn*logn)
这样有O(nlog3n),会超时
这时可以把10^9分成两个4位部分,预处理然后询问O(1)
代码1勉强能过90分,总用时24572ms
代码2有100分,总用时7288ms
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 typedef long long lol; 8 int n,m; 9 int c,ans; 10 int sum[400001],a[100001]; 11 int phi[10001],cnt,ts[400001]; 12 int get_phi(int N) 13 {int i; 14 int res=N,x=N; 15 for (i=2;i*i<=N;i++) 16 { 17 if (x%i) continue; 18 res=res/i*(i-1); 19 while (x%i==0) x/=i; 20 } 21 if (x!=1) res=res/x*(x-1); 22 return res; 23 } 24 void pre(lol p) 25 { 26 phi[0]=p;cnt=0; 27 while (p!=1) 28 { 29 int t=get_phi(p); 30 phi[++cnt]=t; 31 p=t; 32 } 33 phi[++cnt]=1; 34 } 35 int qpow(int x,int y,int p,bool &ok) 36 { 37 int res=1;ok=0; 38 while (y) 39 { 40 if (res*x>=p) ok=1; 41 if (y&1) res=1ll*res*x%p; 42 x=1ll*x*x%p; 43 y>>=1; 44 } 45 return res; 46 } 47 int cal(int x,int k) 48 { 49 int res=x; 50 bool ok; 51 if (x>=phi[k]) res=res%phi[k]+phi[k]; 52 while (k) 53 { 54 res=qpow(c,res,phi[k-1],ok); 55 if (ok) res+=phi[k-1]; 56 k--; 57 } 58 return res; 59 } 60 void build(int rt,int l,int r) 61 { 62 if (l==r) 63 { 64 sum[rt]=a[l]%phi[0]; 65 return; 66 } 67 int mid=(l+r)>>1,ls=rt<<1,rs=rt<<1|1; 68 build(ls,l,mid); 69 build(rs,mid+1,r); 70 sum[rt]=(sum[ls]+sum[rs])%phi[0]; 71 } 72 void update(int rt,int l,int r,int L,int R) 73 { 74 if (ts[rt]>=cnt) return; 75 if (l==r) 76 { 77 ts[rt]++; 78 sum[rt]=cal(a[l],ts[rt]); 79 return; 80 } 81 int mid=(l+r)>>1,ls=rt<<1,rs=rt<<1|1; 82 if (L<=mid) update(ls,l,mid,L,R); 83 if (R>mid) update(rs,mid+1,r,L,R); 84 sum[rt]=(sum[ls]+sum[rs])%phi[0]; 85 ts[rt]=min(ts[ls],ts[rs]); 86 } 87 lol query(int rt,int l,int r,int L,int R) 88 { 89 if (l>=L&&r<=R) 90 { 91 return sum[rt]; 92 } 93 int mid=(l+r)/2,ls=rt<<1,rs=rt<<1|1; 94 lol s=0; 95 if (L<=mid) s=query(ls,l,mid,L,R); 96 if (R>mid) s+=query(rs,mid+1,r,L,R); 97 s%=phi[0]; 98 return s; 99 } 100 int main() 101 {lol p; 102 int l,r,i; 103 int opt; 104 cin>>n>>m>>p>>c; 105 for (i=1;i<=n;i++) 106 scanf("%d",&a[i]); 107 pre(p); 108 build(1,1,n); 109 for (i=1;i<=m;i++) 110 { 111 scanf("%d%d%d",&opt,&l,&r); 112 if (opt==1) 113 { 114 ans=query(1,1,n,l,r); 115 printf("%d\n",ans); 116 } 117 else 118 { 119 update(1,1,n,l,r); 120 } 121 } 122 }
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 typedef long long lol; 8 int n,m; 9 int c,ans; 10 int sum[400001],a[100001],pw1[51][10001],pw2[51][10001]; 11 int phi[10001],cnt,ts[400001]; 12 bool ok1[51][10001],ok2[51][10001]; 13 int get_phi(int N) 14 {int i; 15 int res=N,x=N; 16 for (i=2;i*i<=N;i++) 17 { 18 if (x%i) continue; 19 res=res/i*(i-1); 20 while (x%i==0) x/=i; 21 } 22 if (x!=1) res=res/x*(x-1); 23 return res; 24 } 25 void pre(lol p) 26 { 27 phi[0]=p;cnt=0; 28 while (p!=1) 29 { 30 int t=get_phi(p); 31 phi[++cnt]=t; 32 p=t; 33 } 34 phi[++cnt]=1; 35 } 36 int qpow(int x,int y,int p) 37 { 38 return (1ll*pw1[p][y%10000]*pw2[p][y/10000])%phi[p]; 39 } 40 int cal(int x,int k) 41 { 42 int res=x,pre; 43 bool ok=0; 44 if (res>=phi[k]) ok=1; 45 while (k) 46 { 47 if (ok) res=res%phi[k]+phi[k]; 48 pre=res; 49 res=qpow(c,res,k-1); 50 if (log(phi[k-1])/log(c)<=pre) ok=1; 51 else ok=0; 52 k--; 53 } 54 return res; 55 } 56 void build(int rt,int l,int r) 57 { 58 if (l==r) 59 { 60 sum[rt]=a[l]%phi[0]; 61 return; 62 } 63 int mid=(l+r)>>1,ls=rt<<1,rs=rt<<1|1; 64 build(ls,l,mid); 65 build(rs,mid+1,r); 66 sum[rt]=(sum[ls]+sum[rs])%phi[0]; 67 } 68 void update(int rt,int l,int r,int L,int R) 69 { 70 if (ts[rt]>=cnt) return; 71 if (l==r) 72 { 73 ts[rt]++; 74 sum[rt]=cal(a[l],ts[rt]); 75 return; 76 } 77 int mid=(l+r)>>1,ls=rt<<1,rs=rt<<1|1; 78 if (L<=mid) update(ls,l,mid,L,R); 79 if (R>mid) update(rs,mid+1,r,L,R); 80 sum[rt]=(sum[ls]+sum[rs])%phi[0]; 81 ts[rt]=min(ts[ls],ts[rs]); 82 } 83 lol query(int rt,int l,int r,int L,int R) 84 { 85 if (l>=L&&r<=R) 86 { 87 return sum[rt]; 88 } 89 int mid=(l+r)/2,ls=rt<<1,rs=rt<<1|1; 90 lol s=0; 91 if (L<=mid) s=query(ls,l,mid,L,R); 92 if (R>mid) s+=query(rs,mid+1,r,L,R); 93 s%=phi[0]; 94 return s; 95 } 96 int main() 97 {lol p; 98 int l,r,i,j; 99 int opt; 100 cin>>n>>m>>p>>c; 101 for (i=1;i<=n;i++) 102 scanf("%d",&a[i]); 103 pre(p); 104 build(1,1,n); 105 for (i=0;i<=cnt;i++) 106 { 107 pw1[i][0]=1; 108 for (j=1;j<=10000;j++) 109 { 110 pw1[i][j]=1ll*pw1[i][j-1]*c%phi[i]; 111 } 112 pw2[i][0]=1; 113 for (j=1;j<=10000;j++) 114 { 115 pw2[i][j]=1ll*pw2[i][j-1]*pw1[i][10000]%phi[i]; 116 } 117 } 118 for (i=1;i<=m;i++) 119 { 120 scanf("%d%d%d",&opt,&l,&r); 121 if (opt==1) 122 { 123 ans=query(1,1,n,l,r); 124 printf("%d\n",ans); 125 } 126 else 127 { 128 update(1,1,n,l,r); 129 } 130 } 131 }