gym 102875A -- Array(未更新完)
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                gym 102875A -- Array(未更新完)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                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; }總結
以上是生活随笔為你收集整理的gym 102875A -- Array(未更新完)的全部內容,希望文章能夠幫你解決所遇到的問題。