链接:https://www.nowcoder.com/acm/contest/132/E
来源:牛客网
题目描述
给一个长为n的序列,m次操作,每次操作:
1.区间加
2.对于区间,查询 ,一直到-
请注意每次的模数不同。
输入描述:
第一行两个整数 n,m 表示序列长度和操作数 接下来一行,n个整数,表示这个序列 接下来m行,可能是以下两种操作之一: 操作1:区间[l,r]加上 x 操作2:查询区间[l,r]的那个式子mod p的值
输出描述:
对于每个询问,输出一个数表示答案
示例1
输入
复制
6 4 1 2 3 4 5 6 2 1 2 10000007 2 2 3 5 1 1 4 1 2 2 4 10
输出
复制
1 3 1
备注:
n , m <= 500000 序列中每个数在 [1,2e9] 内,x <= 2e9 , p <= 2e7
降幂公式的简单应用,存一发欧拉线性筛的板子。。。。。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define maxn 500005
#define mod 20000007
#define ll long long
bool isp[mod];
ll c[maxn],a[maxn];
int pri[mod/10],phi[mod];
void init(int n)//欧拉函数线性筛
{
int p=0;
for(int i=2;i<=n;i++)
{
if(isp[i]==0)
pri[++p]=i,phi[i]=i-1;
for(int j=1;j<=p && i*pri[j]<=n;j++)
{
isp[i*pri[j]]=1;
if(i%pri[j]==0)
{
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
else
phi[i*pri[j]]=phi[i]*(pri[j]-1);
}
}
}
ll Mod(ll x,ll y)
{
return x>=y?(x%y+y):x;
}
ll q(ll x,ll y,ll p)
{
ll res=1;
while(y)
{
if(y%2)
res=Mod(res*x,p);
x=Mod(x*x,p);
y/=2;
}
return res;
}
void sum(ll x,ll d,ll n)
{
while(x<=n)
c[x]+=d,x+=x&-x;
}
ll find(ll x)
{
ll res=0;
while(x)
res+=c[x],x-=x&-x;
return res;
}
ll dfs(ll l,ll r,ll p)
{
ll val=find(l);
if(l==r || p==1)
return Mod(val,p);
return q(Mod(val,p),dfs(l+1,r,phi[p]),p);
}
int main(void)
{
init(mod-5);
int n,q;
ll l,r,t,x;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
sum(i,a[i]-a[i-1],n);
}
while(q--)
{
scanf("%lld%lld%lld%lld",&t,&l,&r,&x);
if(t==1)
sum(l,x,n),sum(r+1,-x,n);
else
printf("%lld\n",dfs(l,r,x)%x);
}
return 0;
}
/*
6 4
1 2 3 4 5 6
2 1 2 10000007
2 2 3 5
1 1 4 1
2 2 4 10
*/