bzoj4869 [Shoi2017]相逢是问候

Posted wfj_2048

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4869 [Shoi2017]相逢是问候相关的知识,希望对你有一定的参考价值。

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

Sample Output

0
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 }

 

以上是关于bzoj4869 [Shoi2017]相逢是问候的主要内容,如果未能解决你的问题,请参考以下文章

bzoj4869 [Shoi2017]相逢是问候

BZOJ4869:[SHOI2017]相逢是问候——题解

Bzoj4869: [Shoi2017]相逢是问候

bzoj4869 [Shoi2017]相逢是问候

bzoj 4869: [Shoi2017]相逢是问候

bzoj4869[Shoi2017]相逢是问候 线段树+扩展欧拉定理