P5071 [Ynoi2015] 此时此刻的光辉 题解
题目描述
给定长为 \(n\) 的序列 \(a\) , \(m\) 次查询 \(d(\prod_{i=l}^ra_i)\bmod 19260817\) 的值。
数据范围
- \(1\le n,m\le 10^5,1\le a_i\le 10^9\) 。
时间限制 \(\texttt{2.5s}\) ,空间限制 \(\texttt{500MB}\) 。
分析
显然不同质因子对约数个数的贡献互相独立,考虑根号分治:
-
对 \(\le B\) 的质因子,用前缀和维护出现次数。
-
对 \(\gt B\) 的质因子,每个数至多有 \(\log_Bv\) 个。
将所有质因子摊成 \(\mathcal O(n\log_Bv)\) 的数组,询问转化为区间内 \(\big(\) 不同元素出现次数 \(+1\big)\) 的乘积。
记录每种颜色(每个质因子)出现次数,莫队维护。
注意 \(\mathcal O(n\log v)\) 分解质因数是过不去的,需要改为试除 \(\sqrt v\) 内的所有质因子。
时间复杂度 \(\mathcal O(n\frac{\sqrt v}{\log v}+(n+m)\frac{\sqrt B}{\log B}+n\sqrt m\log_Bv)\) ,取 \(B=v^\frac 13\) 即可通过。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5,B=1000,mod=19260817;
int k,m,n,cnt,cur=1;
int b[maxn],p[maxn],buc[3*maxn],inv[2*maxn];
int bel[maxn],res[maxn],s[170][maxn];
map<int,int> id;
vector<int> vec[maxn];
struct quer
{
int l,r,id;
}f[maxn];
inline int qpow(int a,int k)
{
int res=1;
for(;k;a=1ll*a*a%mod,k>>=1) if(k&1) res=1ll*res*a%mod;
return res;
}
inline void init(int n)
{
for(int i=2;i<=n;i++)
{
if(!b[i]) p[++cnt]=i,id[i]=cnt;
for(int j=1;j<=cnt&&i*p[j]<=n;j++)
{
b[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
for(k=1;p[k+1]<=B;k++) ;
}
inline bool cmp(quer a,quer b)
{
if(bel[a.l]!=bel[b.l]) return bel[a.l]<bel[b.l];
return bel[a.l]&1?a.r<b.r:a.r>b.r;
}
inline void add(int x)
{
for(auto p:vec[x]) buc[p]++,cur=1ll*cur*inv[buc[p]]%mod*(buc[p]+1)%mod;
}
inline void del(int x)
{
for(auto p:vec[x]) cur=1ll*cur*inv[buc[p]+1]%mod*buc[p]%mod,buc[p]--;
}
int main()
{
scanf("%d%d",&n,&m),init(32000);
for(int i=1;i<=2*n+5;i++) inv[i]=qpow(i,mod-2);
for(int i=1,x=0;i<=n;i++)
{
for(int j=1;j<=k;j++) s[j][i]=s[j][i-1];
scanf("%d",&x);
for(int j=1;p[j]*p[j]<=x;j++)
while(x%p[j]==0)
{
x/=p[j];
if(j<=k) s[j][i]++;
else vec[i].push_back(j);
}
if(x==1) continue;
if(!id.count(x)) id[x]=++cnt;
if(id[x]<=k) s[id[x]][i]++;
else vec[i].push_back(id[x]);
}
for(int i=1;i<=n;i++) bel[i]=(i-1)/B+1;
for(int i=1;i<=m;i++) scanf("%d%d",&f[i].l,&f[i].r),f[i].id=i;
sort(f+1,f+m+1,cmp);
for(int i=1,l=1,r=0;i<=m;i++)
{
while(l>f[i].l) add(--l);
while(r<f[i].r) add(++r);
while(l<f[i].l) del(l++);
while(r>f[i].r) del(r--);
int now=cur;
for(int j=1;j<=k;j++) now=now*(s[j][f[i].r]-s[j][f[i].l-1]+1ll)%mod;
res[f[i].id]=now;
}
for(int i=1;i<=m;i++) printf("%d\n",res[i]);
return 0;
}
本文来自博客园,作者:peiwenjun,转载请注明原文链接:https://www.cnblogs.com/peiwenjun/p/17537367.html
浙公网安备 33010602011771号