题意:
分析:
- 暴力
\(O(nm\log )\) 模拟,\(p=2\) 的点判奇偶性,期望得分 \(20pts\)
- 正解
我们发现 \(c\) 恒定,所以经过一系列操作后,每一个元素变为了 \(\large x^{c^{c^{\dots {a_i}}}}\)
我们发现这个形式很欧拉定理,因为欧拉定理对于单个数一旦累计次方超过一定程度,值就成 \(1\) 不变了,我们由已知结论得到,这个次数大约是 \(\log p\) 级别的,也就是说对于每一个元素只有前 $\log $ 次操作是有效的
所以我们预处理出来每一个数前 \(\log\) 次操作,然后按照欧拉定理分 $\log $ 层,所以预处理的复杂度是 \(O(n\log^2)\)
(因为我们使用了光速幂,所以复杂度是 \(2\) 只 $\log $)
然后我们需要线段树维护区间修改操作次数的最小值,一旦区间修改操作大于 $ \log$ 直接返回 ,然后顺便维护区间和值
代码:
#include<bits/stdc++.h>
#define lc rt<<1
#define rc rt<<1|1
using namespace std;
namespace zzc
{
long long read()
{
long long x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
const long long maxn = 5e4+5;
const long long maxs = 1e4+5;
long long cnt[maxn<<2],v[maxn<<2];
long long s1[maxs][30],s2[maxs][30],f[maxn][30][30],a[maxn],g[30],phi[30];
bool b1[maxs][30],b2[maxs][30],b[maxn][30][30];
long long n,m,p,c,len;
long long get_phi(long long x)
{
long long res=x;
for(int i=2;i*i<=x;i++)
{
if(x%i) continue;
res=res*(i-1)/i;
while(x%i==0) x/=i;
}
if(x>1) res=res*(x-1)/x;
return res;
}
void init()
{
long long tmp=p;
phi[0]=tmp;
while(tmp!=1)
{
tmp=get_phi(tmp);
phi[++len]=tmp;
}
phi[++len]=1;
for(int i=0;i<=len;i++) g[i]=__gcd(c,phi[i]);
//¹âËÙÃÝ
for(int j=0;j<=len;j++)
{
s2[0][j]=1;
for(int i=1;i<=10000;i++)
{
s2[i][j]=s2[i-1][j]*c;
if(s2[i][j]>=phi[j])
{
s2[i][j]%=phi[j];
b2[i][j]=true;
}
b2[i][j]|=b2[i-1][j];
}
}
for(int j=0;j<=len;j++)
{
s1[0][j]=1;
b1[1][j]=b2[10000][j];
for(int i=1;i<=10000;i++)
{
s1[i][j]=s1[i-1][j]*s2[10000][j];
if(s1[i][j]>=phi[j])
{
s1[i][j]%=phi[j];
b1[i][j]=true;
}
b1[i][j]|=b1[i-1][j];
}
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<=len;j++)
{
f[i][0][j]=a[i]%phi[j];
if(a[i]>=phi[j]) b[i][0][j]=true;
}
for(int j=1;j<=len;j++)
{
f[i][j][len]=0;
for(int k=0;k<len;k++)
{
f[i][j][k]=s1[f[i][j-1][k+1]/10000][k]*s2[f[i][j-1][k+1]%10000][k];
b[i][j][k]=b1[f[i][j-1][k+1]/10000][k]|b2[f[i][j-1][k+1]%10000][k];
if(f[i][j][k]>=phi[k])
{
f[i][j][k]%=phi[k];
b[i][j][k]=true;
}
if(g[k]!=1&&b[i][j-1][k+1])
{
f[i][j][k]=f[i][j][k]*s1[phi[k+1]/10000][k]%phi[k]*s2[phi[k+1]%10000][k];
if(f[i][j][k]>=phi[k])
{
f[i][j][k]%=phi[k];
b[i][j][k]=true;
}
b[i][j][k]|=b1[phi[k+1]/10000][k]|b2[phi[k+1]%10000][k];
}
}
}
}
return ;
}
void pushup(int rt)
{
v[rt]=v[lc]+v[rc];
cnt[rt]=min(cnt[lc],cnt[rc]);
}
void build(int rt,int l,int r)
{
if(l==r)
{
v[rt]=a[l];
cnt[rt]=0;
return ;
}
int mid=(l+r)>>1;
build(lc,l,mid);build(rc,mid+1,r);
pushup(rt);
}
void modify(int rt,int l,int r,int ql,int qr)
{
if(ql>r||l>qr||cnt[rt]>=len) return ;
if(l==r)
{
cnt[rt]++;
v[rt]=f[l][cnt[rt]][0]%p;
return ;
}
int mid=(l+r)>>1;
if(cnt[lc]<len) modify(lc,l,mid,ql,qr);
if(cnt[rc]<len) modify(rc,mid+1,r,ql,qr);
pushup(rt);
}
long long query(int rt,int l,int r,int ql,int qr)
{
if(ql>r||qr<l) return 0;
if(ql<=l&&r<=qr) return v[rt]%p;
int mid=(l+r)>>1;
return (query(lc,l,mid,ql,qr)+query(rc,mid+1,r,ql,qr))%p;
}
void work()
{
int opt,l,r;
n=read();m=read();p=read();c=read();
for(int i=1;i<=n;i++) a[i]=read();
init();
build(1,1,n);
for(int i=1;i<=m;i++)
{
opt=read();l=read();r=read();
if(opt==0) modify(1,1,n,l,r);
else printf("%lld\n",query(1,1,n,l,r));
}
}
}
int main()
{
zzc::work();
return 0;
}