题目
给一一个n<=4e5的序列a[],ai<=300
两种操作,操作数q<=2e5
一种是区间[l,r]乘上一个值x
另一种是询问区间[l,r]乘积的欧拉函数值
思路来源
各路cf神仙代码
题解1
维护区间积和区间或,
先把300以内的质数筛出来,然后每个数质因数分解
每个数有哪些质数对应用位运算压位,bitset也可以
这样两个数相乘的时候,它们乘积的质因子就是二者的并集
求欧拉函数的时候,先求区间积,
然后看质因子有哪些,
压位的第i位为1说明有prime[i],乘以prime[i]/(prime[i]-1)即可
由于是mod意义下的运算,再先搞一下逆元
代码1
#include<iostream>
#include<cstdio>
#include<cstring>
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;j<cnt;++j)
{
ll k=i*prime[j];
if(k>300)break;
ok[k]=1;
if(i%prime[j]==0)break;
}
}
for(ll i=2;i<=300;++i)
{
ll tmp=i;
for(int j=0;j<cnt;++j)
{
if(prime[j]*prime[j]>tmp)break;
if(tmp%prime[j]==0)
{
mask[i]|=(1ll<<id[prime[j]]);
while(tmp%prime[j]==0)
tmp/=prime[j];
}
}
if(tmp>1)mask[i]|=(1ll<<id[tmp]);
}
inv[1]=1;
for(ll i=2;i<=300;++i)
inv[i]=modpow(i,mod-2,mod);
}
int main()
{
init();
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i)
scanf("%I64d",a+i);
build(1,1,n);
while(q--)
{
int l,r,v;
scanf("%s%d%d",op,&l,&r);
if(op[0]=='M')
{
scanf("%d",&v);
update(1,1,n,l,r,dat(v,mask[v]));
}
else
{
dat ans=query(1,1,n,l,r);
for(int i=0;i<cnt;++i)
{
if(ans.mask&(1ll<<i))
(ans.mul*=(prime[i]-1)*inv[prime[i]]%mod)%=mod;
}
printf("%I64d\n",ans.mul);
}
}
return 0;
}