解析:
再是欧拉线性筛
最后是拓展欧拉定理
还有小的知识是树状数组的区间更新+单点查询 链接
上官方题解
先线性筛phi
然后考虑用拓展欧拉定理降幂
(这里a的指数部分应该是)
我们发现对一个数取欧拉函数,log次就会变成1,而任何数模1肯定=0,所以就可以算出来了。
然而这么做还会有一些小问题。
首先我们发现后面的phi[p]这一项是可能不会加的
这个怎么办呢?
因为这个不断地幂次增长速度极快,很少几项就能够增长到远大于模数的地步
那就先暴力的处理前面几项,然后再正常做,这样就减少了讨论次数
然后加点特判即可
总复杂度O( p + mlognlog*(v) )
这里需要注意的地方有两点
1.上面的x必须是完整的值。例如题目中a[l]^(a[l+1]^(a[l+2]^(a[l+3]^(......a[r])中计算a[l+1]是否需要加上时,是依据(a[l+1]^(a[l+2]^(a[l+3]^(......a[r])>?来决定的,不是a[l+1]>?来决定的
2.在dfs返回指数k时,计算a[i]^k必须要先让a[i]%p..........这个具体的我也不知道为什么,反正没有就只能过60%的样例
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 2e7+10;
const int MAX = 5e5+100;
int prime[MAXN],mark[MAXN];
int tot,phi[MAXN];
ll btree[MAX];
int n;
ll a[MAX];
void getphi(int N)
{
phi[1]=1;
tot=0;
for(int i=2;i<=N;i++)
{
if(!mark[i])
{
prime[++tot]=i;
phi[i]=i-1;
}
for(int j=1;j<=tot;j++)
{
if(i*prime[j]>N) break;
mark[i*prime[j]]=1;
if(i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else
{
//phi[i*prime[j]]=phi[i]*phi[prime[j]];
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
}
inline int lowbit(int x)
{
return x&(-x);
}
void add(int l,ll x) //区间更新
{
for(int i=l;i<=n;i+=lowbit(i))
{
btree[i]+=x;
}
}
ll query(int l) //单点查询
{
ll sum=0;
for(int i=l;i>0;i-=lowbit(i))
sum+=btree[i];
return sum;
}
ll quick(ll a,ll b,ll p,int& ok)
{
ll ans=1;
while(b)
{
if(b&1)
{
if(ans*a>=p) ok=1;
ans=ans*a%p;
}
if(a*a>=p) ok=1;
a=a*a%p;
b=b>>1;
}
return ans;
}
ll dfs(int now,int r,ll p)
{
ll tmp=query(now);
if(now==r||p==1)
{
//if(cnt!=0)
return tmp%p+(tmp>=p?p:0);
/*else
return tmp%p;*/
}
/*if(p==1)
{
//ll tmp=query(now);
//if(cnt!=0)
return 1;
//else
//return 0;
}*/
ll k=dfs(now+1,r,(ll)phi[p]);
int ok=0;
if(tmp>=p) ok=1,tmp=tmp%p; //!!!tmp=tmp%p
ll ans= quick(tmp,k,p,ok);
if(ok)
{
ans+=p;
}
//if(cnt!=0)
return ans;
//else
// return ans%p;
}
int main()
{
getphi(MAXN-2);
int m;
scanf("%d%d",&n,&m);
a[0]=0;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
//add(i,a[i]);
//add(i+1,-a[i]);
add(i,a[i]-a[i-1]);
}
for(int i=0;i<m;i++)
{
int l,r,mode;
ll x;
scanf("%d%d%d%lld",&mode,&l,&r,&x);
if(mode==1)
{
add(l,x);
add(r+1,-x);
}
else
{
printf("%lld\n",dfs(l,r,x)%x); //%x用于去除dfs内a[l]%x时加上x的情况
}
}
return 0;
}