Description
dC 在秒了BZOJ 上所有的数论题后,感觉萌萌哒,想出了这么一道水题,来拯救日益枯竭的水题资源。
给定一个长度为 n的正整数序列A,有q次询问,每次询问一段区间内所有元素乘积的φ(φ(n)代表1~n 中与n互质的数的个数) 。由于答案可能很大,所以请对答案 mod 10^6 + 777。
(本题强制在线,所有询问操作的l,r都需要 xor上一次询问的答案 lastans,初始时,lastans = 0)
1 <= N <= 50000
1 <= Q <= 100000
1 <= Ai <= 10^6
Solution
考虑φ的一种求法,注意到一种质因子只会算一次,等价于我们求区间内所有出现至少一次的质因子的贡献
我们开n棵线段树,对于a[i]的一个质因子x,我们在第i棵线段树上删去x在last[x]位置上的贡献,增加x在i上的贡献。这里显然为 x − 1 x \frac{x-1}{x} xx−1。正确性的话可以yy一下
然后就很简单了,查询l到r就在第r棵线段树上求区间乘积就行了
这道题需要注意下分解质因数的方法。可以记low[i]为i的最小质因子然后每次用low[i]除,可以证明这样是比较优秀的
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
const int MOD=1000777;
const int N=50005;
struct treeNode {
int l,r,prod;
} t[N*205];
int prime[MOD*2],rec[MOD*2],ny[MOD*2],a[N],p[N];
int last[MOD*2],root[N],low[MOD*2],tot;
bool not_prime[MOD*2];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
int ksm(int x,int dep) {
int ret=1;
for (;dep;dep>>=1) {
(dep&1)?(ret=1LL*ret*x%MOD):0;
x=1LL*x*x%MOD;
}
return ret;
}
void pre_work(int n) {
ny[1]=1;
rep(i,2,n) {
if (!not_prime[i]) {
prime[++prime[0]]=i;
ny[i]=ksm(i,MOD-2);
low[i]=rec[i]=i;
}
for (int j=1;1LL*i*prime[j]<=n&&j<=prime[0];++j) {
not_prime[i*prime[j]]=1;
ny[i*prime[j]]=1LL*ny[i]*ny[prime[j]]%MOD;
low[i*prime[j]]=rec[i*prime[j]]=prime[j];
if (i%prime[j]==0) {
low[i*prime[j]]=low[i]*prime[j];
break;
}
}
}
}
void modify(int &now,int pre,int tl,int tr,int x,int v) {
t[now=++tot]=t[pre]; t[now].prod=1LL*t[now].prod*v%MOD;
if (tl==tr) return ;
int mid=(tl+tr)>>1;
if (x<=mid) modify(t[now].l,t[pre].l,tl,mid,x,v);
else modify(t[now].r,t[pre].r,mid+1,tr,x,v);
}
int query(int now,int tl,int tr,int l,int r) {
if (r<l) return 1;
if (tl==l&&tr==r) return t[now].prod;
int mid=(tl+tr)>>1;
if (r<=mid) return query(t[now].l,tl,mid,l,r);
if (l>mid) return query(t[now].r,mid+1,tr,l,r);
return 1LL*query(t[now].l,tl,mid,l,mid)*query(t[now].r,mid+1,tr,mid+1,r)%MOD;
}
void build(int &now,int l,int r) {
t[now=++tot].prod=1;
if (l==r) return ;
int mid=(l+r)>>1;
build(t[now].l,l,mid);
build(t[now].r,mid+1,r);
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
pre_work(MOD); p[0]=1;
int n=read(),m=read();
build(root[0],1,n);
rep(i,1,n) {
root[i]=root[i-1];
a[i]=read(); int tmp=a[i];
p[i]=1LL*p[i-1]*a[i]%MOD;
for (;tmp!=1;) {
int y=low[tmp],x=rec[tmp];
for (;tmp%y==0;) tmp/=y;
if (last[x]) modify(root[i],root[i],1,n,last[x],1LL*ny[x-1]*x%MOD);
modify(root[i],root[i],1,n,i,1LL*(x-1)*ny[x]%MOD);
last[x]=i;
}
}
for (int lastans=0;m--;) {
// int l=read(),r=read();
int l=read()^lastans,r=read()^lastans;
lastans=1LL*p[r]*ny[p[l-1]]%MOD;
lastans=1LL*lastans*query(root[r],1,n,l,r)%MOD;
printf("%d\n", lastans);
}
return 0;
}