给一一个n<=4e5的序列a[],ai<=300
两种操作,操作数q<=2e5
一种是区间[l,r]乘上一个值x
另一种是询问区间[l,r]乘积的欧拉函数值
各路cf神仙代码
维护区间积和区间或,
先把300以内的质数筛出来,然后每个数质因数分解
每个数有哪些质数对应用位运算压位,bitset也可以
这样两个数相乘的时候,它们乘积的质因子就是二者的并集
求欧拉函数的时候,先求区间积,
然后看质因子有哪些,
压位的第i位为1说明有prime[i],乘以prime[i]/(prime[i]-1)即可
由于是mod意义下的运算,再先搞一下逆元
#include
#include
#include
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=(1<<20)+5;
const int maxm=4e5+5;
const int maxv=310;
bool ok[maxv];
ll prime[maxv],id[maxv],cnt;
ll inv[maxv],mask[maxv];
int n,q;
ll a[maxm];
char op[20];
ll modpow(ll x,ll n,ll mod)
{
if(n==0)return 1;
ll p=modpow(x,n/2,mod),res=p*p%mod;
if(n&1)(res*=x)%=mod;
return res;
}
struct dat
{
ll mul,mask;
dat():mul(1),mask(0){}
dat(ll a,ll b):mul(a),mask(b){}
dat operator+(const dat &rhs)const
{
return dat((mul*rhs.mul)%mod,mask|rhs.mask);
}
}e[maxn],lazy[maxn];
void pushup(int p)
{
e[p]=e[p<<1]+e[p<<1|1];
}
void build(int p,int l,int r)
{
if(l==r)
{
e[p]=dat(a[l],mask[a[l]]);
return;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
void app(int p,int l,int r,dat v)
{
lazy[p]=lazy[p]+v;
v.mul=modpow(v.mul,(r-l+1)%(mod-1),mod);//费马
e[p]=e[p]+v;
}
void pushdown(int p,int l,int r)
{
int mid=(l+r)>>1;
app(p<<1,l,mid,lazy[p]);
app(p<<1|1,mid+1,r,lazy[p]);
lazy[p]=dat(1,0);
}
void update(int p,int l,int r,int ql,int qr,dat v)
{
if(ql<=l&&r<=qr)
{
app(p,l,r,v);
return;
}
int mid=(l+r)>>1;
pushdown(p,l,r);
if(ql<=mid)update(p<<1,l,mid,ql,qr,v);
if(qr>mid)update(p<<1|1,mid+1,r,ql,qr,v);
pushup(p);
}
dat query(int p,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)return e[p];
int mid=(l+r)>>1;
pushdown(p,l,r);
return (ql<=mid?query(p<<1,l,mid,ql,qr):dat(1,0))+(qr>mid?query(p<<1|1,mid+1,r,ql,qr):dat(1,0));
}
void init()
{
for(ll i=2;i<=300;++i)
{
if(!ok[i])
{
prime[cnt]=i;
id[i]=cnt++;
}
for(ll j=0;j300)break;
ok[k]=1;
if(i%prime[j]==0)break;
}
}
for(ll i=2;i<=300;++i)
{
ll tmp=i;
for(int j=0;jtmp)break;
if(tmp%prime[j]==0)
{
mask[i]|=(1ll<1)mask[i]|=(1ll<