https://www.nowcoder.com/acm/contest/132/E
给定数组A,有2种操作
1.区间更新,a[l]...a[r]都加x
2.求阶乘幂 a[l] ^ (a[l+1] ^ (...a[r-1] ^ a[r]))
解:
区间更新用树状数组
A[i]记录原数组
delta[i]记录a[i]到a[n]共同的增量
xdelta[i] = i * delta[i]
sum[i] = (A[1] + ... + A[i]) + (i + 1) * (delta[1] + ... + delta[i]) - (xdelta[1] + ... + xdelta[i])
阶乘幂用扩展欧拉定理
ps:
ll modp(ll a,ll p){return a >= p ? a % p + p : a;}
ll qk_pow(ll a,ll b,ll p)
{
ll ans = 1;
a = modp(a,p);
while(b){
if(b & 1) ans = modp(ans * a,p);
b >>= 1;
a = modp(a * a,p);
}
return ans;
}
#include
#include
#include
#include
using namespace std;
const int maxn = 5e5 + 5;
const int maxp = 2e7 + 5;
int phi[maxp];
typedef long long ll;
ll A[maxn];
ll delta[maxn];
ll xdelta[maxn];
int n,m;
void init()
{
for(int i = 2;i < maxp;i ++){
if(phi[i] == 0) {
phi[i] = i - 1;
for(int j = i + i;j < maxp;j += i){
if(phi[j] == 0) phi[j] = j;
phi[j] = phi[j] / i * (i - 1);
}
}
}
}
void update(ll arr[],int x,ll k)
{
while(x < maxn){
arr[x] += k;
x += (x & -x);
}
}
ll sum(ll arr[],int x)
{
ll ans = 0;
while(x){
ans += arr[x];
x -= (x & -x);
}
return ans;
}
ll getA(int x)
{
ll ans1 = sum(A,x) + (ll)(x + 1) * sum(delta,x) - sum(xdelta,x);
ll ans2 = 0;
x -- ;
if(x) ans2 = sum(A,x) + (ll)(x + 1) * sum(delta,x) - sum(xdelta,x);
return ans1 - ans2;
}
ll modp(ll a,ll p){return a >= p ? a % p + p : a;}
ll qk_pow(ll a,ll b,ll p)
{
ll ans = 1;
a = modp(a,p);
while(b){
if(b & 1) ans = modp(ans * a,p);
b >>= 1;
a = modp(a * a,p);
}
return ans;
}
ll f(int ql,int qr,int p)
{
if(p == 1) return 1;
ll a = getA(ql);
if(ql == qr ) return modp(a,p);
ll x = f(ql + 1,qr,phi[p]);
ll ans = qk_pow(a,x,p);
return ans;
}
int main()
{
init();
while(scanf("%d%d",&n,&m) != EOF)
{
memset(A,0,sizeof(A));
memset(delta,0,sizeof(delta));
memset(xdelta,0,sizeof(xdelta));
int t;
for(int i = 1;i <= n;i ++){
scanf("%d",&t);
update(A,i,t);
}
int op;
ll l,r,p;
while(m --){
scanf("%d%lld%lld%lld",&op,&l,&r,&p);
if(op == 1){
update(delta,l,p);
update(delta,r + 1,-p);
update(xdelta,l,l * p);
update(xdelta,r + 1,-p * (r + 1));
}
else{
ll ans = f(l,r,p);
ans = (ans % p + p) % p;
printf("%lld\n",ans);
}
}
}
return 0;
}