对于正整数 n,定义欧拉函数 φ(n) 为小于等于 n 且与 n 互质的正整数个数。例如
φ(1) = 1, φ(8) = 4。
给定正整数序列 a1, a2, · · · , an,请依次执行 q 个操作,操作有以下三种类型:
0 i x:修改 ai 的值为 x;
1 l r:查询 φ(al + al+1 + · · · + ar) 的值,输出这个值对 10^9 + 7 取模的结果;
2 l r:查询 φ(al × al+1 × · · · × ar) 的值,输出这个值对 10^9 + 7 取模的结果。
1 ≤ i ≤ n, x ≥ 1, 1 ≤ l ≤ r ≤ n。
n ≤ 50000, q ≤ 100000,Ai及x<=40000操作 0 的个数不超过 20000,所有的 ai、
操作 0 中的 i, x 及操作 1,2 中的 l, r 均在给定的限制下内均匀随机生成
首先对于第1问,考虑到加起来的结果最大也就是2e9,我们可以根号时间复杂来算出phi,又考虑数据随机,用线段树或者树状数组维护和,然后一个单次询问是
考虑第二问,发现乘起来的话就不能根号时间算phi了,但是我们发现每次乘起来质因子是不会有变化的,而每个只要考虑出现了哪些质因子,每种质因子x对所有乘积的贡献是
for(ll i=ans._Find_first();i<ans.size();i=ans._Find_next(i))
质因子个数发现只有4203个,于是就有时间复杂度
#include
#define ll long long
using namespace std;
const ll N = 200010;
const ll mod = 1e9+7;
inline ll read()
{
ll p=0; ll f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
ll prime[N],pri,inv[N],idx[N]; bool v[N];
bitset<4210> bo[N],ans,pb[N];
void init(ll n)
{
memset(v,1,sizeof(v)); v[0] = v[1] = 0; pri = 0;
for(ll i=2;i<=n;i++)
{
if(v[i]) prime[++pri] = i,idx[i] = pri;
for(ll j=1;(j<=pri) && (i*prime[j]<=n);j++)
{
v[i*prime[j]]=0;
if(i%prime[j]==0) break;
}
}
inv[0] = inv[1] = 1; for(ll i=2;i<=n;i++) inv[i] = (mod - mod / i) * inv[mod%i] % mod;
for(ll i=1;i<=n;i++)
{
ll x=i;
for(ll j=1;prime[j]*prime[j]<=x;j++)
{
while(x%prime[j]==0){pb[i].set(j); x/=prime[j];}
}if(x!=1) pb[i].set(idx[x]);
}
}
ll lc[N],rc[N],tot,rt,c[N],s[N];
void link(ll &u,ll L,ll R,ll k,ll cc)
{
if(!u) u=++tot;
if(L==R){bo[u] = pb[cc]; c[u] = s[u] = cc; return ;}
ll mid=(L+R)>>1;
if(k<=mid) link(lc[u],L,mid,k,cc);
else link(rc[u],mid+1,R,k,cc);
c[u] = c[lc[u]] + c[rc[u]];
s[u] = (s[lc[u]] * s[rc[u]]) % mod;
bo[u] = bo[lc[u]] | bo[rc[u]];
}
ll qry1(ll u,ll L,ll R,ll l,ll r)
{
if(L==l && R==r) return c[u];
ll mid=(L+R)>>1;
if(r<=mid) return qry1(lc[u],L,mid,l,r);
else if(l>mid) return qry1(rc[u],mid+1,R,l,r);
else return qry1(lc[u],L,mid,l,mid) + qry1(rc[u],mid+1,R,mid+1,r);
}
ll qry2(ll u,ll L,ll R,ll l,ll r)
{
if(L==l && R==r){ans |= bo[u]; return s[u];}
ll mid=(L+R)>>1;
if(r<=mid) return qry2(lc[u],L,mid,l,r);
else if(l>mid) return qry2(rc[u],mid+1,R,l,r);
else return qry2(lc[u],L,mid,l,mid) * qry2(rc[u],mid+1,R,mid+1,r) % mod;
}
ll qpow(ll x,ll k,ll mo){ll ss=1; while(k){if(k&1) ss=ss*x%mo; x=x*x%mo; k>>=1;} return ss;}
int main()
{
init(40000);
ll n = read(); ll m = read();
rt=tot=0; for(ll i=1;i<=n;i++) link(rt,1,n,i,read());
while(m--)
{
ll op = read();
if(op==0){ll k = read(); link(rt,1,n,k,read());}
else if(op==1)
{
ll l=read(); ll r=read(); ll sum = qry1(rt,1,n,l,r);
ll x = sum;
for(ll i=1;prime[i] * prime[i] <= x;i++)
{
if(x%prime[i]==0)
{
sum = sum * inv[prime[i]] % mod * (prime[i] - 1) % mod;
while(x%prime[i]==0) x/=prime[i];
}
}
if(x!=1) sum = sum * qpow(x,mod-2,mod) % mod * (x-1) % mod;
printf("%lld\n",sum);
}
else
{
ll l=read(); ll r=read(); ans.reset();
ll sum = qry2(rt,1,n,l,r);
for(ll i=ans._Find_first();i1) % mod;
printf("%lld\n",sum);
}
}
return 0;
}