题目:
https://www.luogu.org/problemnew/show/P3747
分析:
幂次可以考虑扩展欧拉定理。
对于一个模数 p p p,使得 ϕ ( ϕ ( . . . ϕ ( p ) ) ) = 1 \phi(\phi(...\phi(p)))=1 ϕ(ϕ(...ϕ(p)))=1,最少 ϕ \phi ϕ的个数 l i m lim lim。
每次的 c c c是一样的,显然当一个位置修改次数大于 l i m lim lim。这个位置就不变了。
维护一棵线段树,每个节点维护这个区间是否所有的点都到达了 l i m lim lim和区间和。修改直接暴力到叶子节点,对于每一个叶子结点跑扩展欧拉。幂次要预处理。
代码:
// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include
#include
#include
#define LL long long
const int maxn=5e4+7;
using namespace std;
int n,m,mod,c,op,x,y,lim;
int a[maxn],phi[101];
struct node{
int l,r,data,sum;
}t[maxn*8];
int getphi(int p)
{
int tmp=1;
for (int i=2;i<=trunc(sqrt(p));i++)
{
if (p%i==0)
{
tmp*=i-1;
p/=i;
while (p%i==0) tmp*=i,p/=i;
}
}
if (p>1) tmp*=p-1;
return tmp;
}
void build(int p,int l,int r)
{
if (l==r)
{
t[p].sum=a[l];
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].sum=(t[p*2].sum+t[p*2+1].sum)%mod;
}
LL power(LL x,LL y,LL p)
{
LL ret=1;
int flag=0,flag1=0;
while (y)
{
if (y&1)
{
ret*=x;
flag=flag1;
if (ret>=p) ret%=p,flag=1;
}
if (x>=p) flag1=1,x%=p;
x=x*x;
if (x>=p) flag1=1,x%=p;
y>>=1;
}
if (flag) return ret+p;
return ret;
}
LL calc(int k,int x,int d)
{
if (!k)
{
if (x>=phi[d]) return x%phi[d]+phi[d];
else return x;
}
if (phi[d]==1) return 1;
LL y=calc(k-1,x,d+1);
return power(c,y,phi[d]);
}
void ins(int p,int l,int r,int x,int y)
{
if (t[p].data>lim) return;
if (l==r)
{
t[p].data++;
t[p].sum=(LL)calc(t[p].data,a[l],0)%mod;
return;
}
int mid=(l+r)/2;
if (y<=mid) ins(p*2,l,mid,x,y);
else if (x>mid) ins(p*2+1,mid+1,r,x,y);
else
{
ins(p*2,l,mid,x,mid);
ins(p*2+1,mid+1,r,mid+1,y);
}
t[p].sum=(t[p*2].sum+t[p*2+1].sum)%mod;
t[p].data=min(t[p*2].data,t[p*2+1].data);
}
int query(int p,int l,int r,int x,int y)
{
if ((l==x) && (r==y)) return t[p].sum;
int mid=(l+r)/2;
if (y<=mid) return query(p*2,l,mid,x,y);
else if (x>mid) return query(p*2+1,mid+1,r,x,y);
else return (query(p*2,l,mid,x,mid)+query(p*2+1,mid+1,r,mid+1,y))%mod;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&mod,&c);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,1,n);
phi[0]=mod;
while (phi[lim]!=1)
{
lim++;
phi[lim]=getphi(phi[lim-1]);
}
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&op,&x,&y);
if (op==0) ins(1,1,n,x,y);
else printf("%d\n",query(1,1,n,x,y));
}
}