[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

Sample Output

0
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 }
View Code1
  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 }
View Code2

 

posted @ 2018-01-17 18:26  Z-Y-Y-S  阅读(307)  评论(3编辑  收藏  举报