gym 102875A – Array
题意:
对于一个数组a,以及数p,
q个操作
1.对于区间[l,r],里面所有数+k
2.对于区间[l,r],里面所有数 * k
3.对于区间[l,r],里面所有数变成k次幂
4.对于区间[l,r],输出里面所有数k次幂的和
5.对于区间[l,r],输出里面所有数的乘积
操作4和5的结果mod p
1<=n<=1e5
2<=p<=30
0<=a<=1e9
1<=q<=1e5
注:我们规定00 = 1
题解:
参考题解
参考题解
第一个题解的方法很妙,因为p的范围很小,所以可以直接用线段树来维护每个区间值为x的数有多少个,f数组用来记录每个数转移成了什么数
num[root<<1][f[root][i]] = num[root<<1][i]
第二个方法在计算快速幂时用欧拉降幂来优化下常数
4月26再看这题
在刷了很多树之后,有些感觉。。但感觉让自己写还是写不出
num[root][i]以root为根的子树中有多少个i
f[root][i] 表示以root为根的子树中原本的i转移成了什么数
因为p很小,所以可以将mod值和pow值(记得取模)提前求好
代码很妙,思路也很好,是个好题
代码:
#include<bits/stdc++.h>
using namespace std;
#define G if(++ip==ie)if(fread(ip=buf,1,SZ,stdin))
#define ri register int
#define iv inline void
using namespace std;
const int SZ=1<<19;
char buf[SZ],*ie=buf+SZ,*ip=ie-1;
inline int in(){G;while(*ip<'-')G;ri x=*ip&15;G;while(*ip>'-'){x*=10;x+=*ip&15;G;}return x;
}
const int N=1e5+5;
int p;
int num[N*4][35],f[N*4][35];
int tmp[35];
void push_down(int root){for(int i=0;i<p;i++){tmp[i]=num[root<<1][i];num[root<<1][i]=0;} for(int i=0;i<p;i++){num[root<<1][f[root][i]]+=tmp[i];}for(int i=0;i<p;i++){tmp[i]=num[root<<1|1][i];num[root<<1|1][i]=0;}for(int i=0;i<p;i++){num[root<<1|1][f[root][i]]+=tmp[i];}for(int i=0;i<p;i++){f[root<<1][i]=f[root][f[root<<1][i]];f[root<<1|1][i]=f[root][f[root<<1|1][i]];}for(int i=0;i<p;i++)f[root][i]=i;
}
int a[N];
void build(int l,int r,int root){for(int i=0;i<p;i++)f[root][i]=i;if(l==r){num[root][a[l]]=1;return ;}int mid=l+r>>1;build(l,mid,root<<1);build(mid+1,r,root<<1|1);for(int i=0;i<p;i++)num[root][i]=num[root<<1][i]+num[root<<1|1][i];
}
int quik(int a,int b){int ans=1;for(;b;b>>=1,a=a*a%p)if(b&1)ans=ans*a%p;return ans;}
int mod[N];
int qpow[35];
/*
num[root][i]以root为根的子树中有多少个i
f[root][i] 表示以root为根的子树中原本的i转移成了什么数
*/
void update(int l,int r,int root,int ql,int qr,int op,int v){if(l>=ql&&r<=qr){if(op==2){//mulfor(int i=0;i<p;i++){tmp[i]=num[root][i];num[root][i]=0;}for(int i=0;i<p;i++){num[root][mod[i*v]]+=tmp[i];f[root][i]=mod[f[root][i]*v];}}else if(op==1){//addfor(int i=0;i<p;i++){tmp[i]=num[root][i];num[root][i]=0;}for(int i=0;i<p;i++){num[root][mod[(i+v)]]+=tmp[i];f[root][i]=mod[(f[root][i]+v)];}}else if(op==3){//^kfor(int i=0;i<p;i++){tmp[i]=num[root][i];num[root][i]=0;}for(int i=0;i<p;i++){num[root][qpow[i]]+=tmp[i];f[root][i]=qpow[f[root][i]];}}return ;}push_down(root);int mid=l+r>>1;if(mid>=ql)update(l,mid,root<<1,ql,qr,op,v);if(mid<qr)update(mid+1,r,root<<1|1,ql,qr,op,v);for(int i=0;i<p;i++)num[root][i]=num[root<<1][i]+num[root<<1|1][i];
}
int ans[35];
void query(int l,int r,int root,int ql,int qr){if(l>=ql&&r<=qr){for(int i=0;i<30;i++)ans[i]+=num[root][i];return ;}push_down(root);int mid=l+r>>1;if(mid>=ql)query(l,mid,root<<1,ql,qr);if(mid<qr)query(mid+1,r,root<<1|1,ql,qr);
}
int main()
{int n;n=in(),p=in();for(int i=1;i<=n;i++)a[i]=in(),a[i]%=p;for(int i=0;i<35*35;i++)mod[i]=i%p;build(1,n,1);int q;q=in();while(q--){int op,l,r,k;op=in(),l=in(),r=in(),k=in();if(op<=2)k%=p;else if(op==3){for(int i=0;i<p;i++)qpow[i]=quik(i,k);}if(op<=3)update(1,n,1,l,r,op,k);else {for(int i=0;i<p;i++)ans[i]=0;query(1,n,1,l,r);if(op==4){int sum=0;for(int i=0;i<p;i++)sum=(sum+quik(i,k)*ans[i])%p;printf("%d\n",sum);}else {int sum=1;for(int i=0;i<p;i++)sum=sum*quik(i,ans[i])%p;printf("%d\n",sum);}}}return 0;
}