洛谷 P3934 [Ynoi Easy Round 2016] 炸脖龙 I
由于扩展欧拉定理 \(a ^ b \equiv \begin{cases} a ^ {b \bmod \varphi (p)} & b < \varphi (p) \\ a ^ {(b \bmod \varphi (p)) + \varphi (p)} & b \ge \varphi (p) \end{cases}\pmod p\),故重新定义 \(a \operatorname {\%} b = \begin{cases} a & a < b \\ (a \bmod b) + b & a \ge b\end{cases}\)。
记答案为 \(f (l, r, p)\),对于 \(l = r\),答案为 \(a _ l \operatorname {\%} p\);对于 \(l < r\),答案为 \(a _ l ^ {f (l + 1, r, \varphi (p))} \operatorname {\%} p\)。
但这时间复杂度是 \(\text O (n ^ 2)\) 的。注意到奇数 \(c > 1\) 的 \(\varphi (c)\) 为偶数,偶数 \(d\) 的 \(\varphi (d) \le d / 2\),故经过不超过 \(\text O (\log p)\) 次递归 \(p\) 会减小到 \(1\),特判这个边界就行了。
一些细节:所有 \(\varphi (p)\) 的值可以线性筛预处理,区间加 / 单点查的部分可以树状数组维护。
时间复杂度 \(\text O (n \log ^ 2 V + V)\)。
#include<cstdio>
#define N 500005
#define M 20000005
using namespace std;
typedef long long ll;
int n,m;
int cnt,p[M/10],phi[M];
ll a[N];
void sieve(int n) {
phi[1]=1;
for(int i=2;i<=n;i++) {
if(!phi[i]) p[++cnt]=i,phi[i]=i-1;
for(int j=1;j<=cnt&&p[j]<=n/i;j++) {
if(i%p[j]==0) {phi[i*p[j]]=phi[i]*p[j]; break;}
phi[i*p[j]]=phi[i]*(p[j]-1);
}
}
}
struct BIT {
ll tr[N];
void add(int p,ll c) {
for(;p<=n;p+=p&-p) tr[p]+=c;
}
ll ask(int p) {
ll res=0;
for(;p;p&=p-1) res+=tr[p];
return res;
}
void add(int l,int r,ll c) {add(l,c),add(r+1,-c);}
} t1;
int mod(long long x,int p) {
if(x<p) return x;
return x%p+p;
}
int qpow(long long x,int y,int p) {
int res=1; x=mod(x,p);
for(;y;y>>=1) {
if(y&1) res=mod(res*x,p);
x=mod(x*x,p);
}
return res;
}
int f(int l,int r,int p) {
a[l]=t1.ask(l);
if(l==r||p==1) return mod(a[l],p);
return qpow(a[l],f(l+1,r,phi[p]),p);
}
int main() {
scanf("%d%d",&n,&m);
sieve(2e7);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),t1.add(i,a[i]-a[i-1]);
for(int i=1,op,x,y,z;i<=m;i++) {
scanf("%d%d%d%d",&op,&x,&y,&z);
if(op==1) t1.add(x,y,z);
else printf("%d\n",f(x,y,z)%z);
}
return 0;
}

浙公网安备 33010602011771号