题意:
给出一个序列a,两种操作
1.将[l,r]这段区间所有的数 ai a i 换为 cai c a i
2.求[l,r]这段区间的和,对p取模
1≤n≤50000; 1≤m≤50000; 1≤p≤100000000; 0<c<p; 0≤ai<p 1 ≤ n ≤ 50000 ; 1 ≤ m ≤ 50000 ; 1 ≤ p ≤ 100000000 ; 0 < c < p ; 0 ≤ a i < p
Solution:
这道题有些类似于BZOJ3884和Codeforces906D
对一个位置执行多次1操作后,φ的值就变成了1,这个位置的值就不变了,可以证明执行操作的次数是log级别的,所以我们建一棵线段树,加一个标记表示这个节点表示的区间是否还会发生变化,不能就跳过,能就在里面暴力赋值,对于每个点先预处理出这个点从初始到不变的所有可能变成的值,最后线段树维护即可
维护的复杂度是 O(nlog2n) O ( n log 2 n ) ,预处理的复杂度是 O(nlog3n) O ( n log 3 n )
然后发现T掉了….
怎么办呢?
发现p的值是1e8,且每次快速幂的指数是一定的,所以说我们可以通过预处理c的不同次幂来优化掉快速幂的log
然后这道题就可以愉快的A掉啦(雾
代码:
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
int n,m,mod,c;
const int N=50010;
int a[N],f[N][30],st[30],cnt;
struct tree{
int l,r,num,len;
int v;
}tr[4*N];
int bq[10010][30],sq[10010][30];
int phi(int x)
{
int t=sqrt(x),ans=x;
for (int i=2;i<=t;i++)
{
if (x%i==0)
{
ans-=ans/i;
while (x%i==0) x/=i;
}
}
if (x>1) ans-=ans/x;
return ans;
}
int fast_pow(int a,int x,int mod)
{
int ans=1;
for (;x;x>>=1,a=1ll*a*a>=mod?1ll*a*a%mod+mod:1ll*a*a%mod)
if (x&1) ans=1ll*a*ans>=mod?1ll*a*ans%mod+mod:1ll*a*ans%mod;
return ans;
}
int fpow(int a,int x,int pos)
{
int mod=st[pos];
long long t=1ll*bq[x/10000][pos]*sq[x%10000][pos];
return t>=mod?t%mod+mod:t%mod;
}
int dfs(int i,int l,int r)
{
if (st[l]==1) return 1;
if (l==r) return a[i]<st[l]?a[i]:a[i]%st[l]+st[l];
int T=dfs(i,l+1,r);
return fpow(c,T,l);
}
void update(int i)
{
tr[i].v=(tr[i<<1].v+tr[i<<1|1].v)%mod;
tr[i].len=tr[i<<1].len+tr[i<<1|1].len;
}
void build(int i,int l,int r)
{
tr[i].l=l,tr[i].r=r;
if (l==r) {
tr[i].len=1;tr[i].v=a[l];return;}
int mid=l+r>>1;
build(i<<1,l,mid);build(i<<1|1,mid+1,r);
update(i);
}
void modify(int i,int l,int r)
{
if (tr[i].len==0) return;
int L=tr[i].l,R=tr[i].r;
if (L>r||l>R) return;
if (L==R){
tr[i].num++;tr[i].v=f[L][tr[i].num];if (tr[i].num==cnt) tr[i].len--;return;}
modify(i<<1,l,r);modify(i<<1|1,l,r);
update(i);
}
int query(int i,int l,int r)
{
int L=tr[i].l,R=tr[i].r;
if (L>r||l>R) return 0;
if (l<=L&&R<=r) return tr[i].v;
return (query(i<<1,l,r)+query(i<<1|1,l,r))%mod;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&mod,&c);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
st[0]=mod;
while (st[cnt]-1) cnt++,st[cnt]=phi(st[cnt-1]);
st[++cnt]=1;
for (int i=0;i<=cnt;i++)
{
for (int j=0;j<=10000;j++)
bq[j][i]=fast_pow(c,j*10000,st[i]);
for (int j=0;j<=10000;j++)
sq[j][i]=fast_pow(c,j,st[i]);
}
for (int i=1;i<=n;i++)
{
if (a[i]==0) {f[i][1]=1;a[i]=1;for (int j=2;j<=cnt;j++)f[i][j]=dfs(i,0,j-1)%mod;a[i]=0;}
else
{
for (int j=1;j<=cnt;j++)
f[i][j]=dfs(i,0,j)%mod;
}
}
build(1,1,n);
for (int p,x,y,i=1;i<=m;i++)
{
scanf("%d%d%d",&p,&x,&y);
if (!p) modify(1,x,y);
else printf("%d\n",query(1,x,y));
}
}