UOJ188题解
我们先枚举一个最大质因子,然后设 \(dp[n][k]\) 为 \(n\) 以内使用了 \(pri[k]\) 以内的质数的数的最大质因子之和,答案就是:
当 \(pri[k]\) 大于 \(\sqrt{n}\) 时,后面相当于变成 \(\sqrt{n}\) 以内所有数的最大质因子之和,可以线性筛,质数个数也可以使用叶筛解决。
考虑这个 \(dp\) 怎么办。
根据上面的东西,我们设一个 \(g[n][k]\) 为 \(n\) 以内使用了 \(pri[k]\) 以内的质数的数的个数。有:
只要一边筛 \(g\) 一边丢到 \(dp\) 数组里边就好了。
但是注意到丢进去的复杂度是 \(O(\frac{n}{\ln^2n})\) 的,考虑优化。。。
这个 \(g\) 是十分经典的叶筛。\(g\) 的定义为仅用过 \([1,pri[k]]\) 的质数,叶筛的 \(f\) 定义为 \([1,pri[k]]\) 的的质数都没被使用过,即最小质因子为 \(pri[k]\)。
转移可以参考这个过程。得到有:
当 \(pri[k]^2\geq n\) 时,有:
转移的话可以使用叶筛的那种转移,滚动数组就好了()
然后,对于 \(pri[k]^2\geq n\) 的情况,相当于令一个若干个区间加上若干个值。我们对 \([1,\lfloor\sqrt{n}\rfloor]\) 和 \(\lfloor\frac{n}{i}\rfloor\) 分开考虑。
对于前者,直接把所有区间找出来加上就好了。复杂度是 \(O(\sum_{i=1}^{\frac{\sqrt{n}}{\ln n}}\min(i,\frac{\sqrt{n}}{i\log i}))\leq O(\sum_{i=1}^{\frac{\sqrt{n}}{\ln n}}\frac{\sqrt{n}}{i\log i})\),后者也是相同的复杂度。
处理 \(g\) 对 \(dp\) 的贡献复杂度过高,考虑直接使用 \(g\) 计算答案:
我们提前使用叶筛处理质数个数,然后后面对着这个直接整除分块就好了。
复杂度是:
加上叶筛,复杂度是 \(O(\frac{n^{\frac{3}{4}}}{\log n})\)。
注意到每次更新的是一段后缀的 \(g\),所以对于后缀完全可以直接动态地维护前缀和。复杂度 \(O(\frac{n^{\frac{3}{4}}}{\log n})\)。
对于前缀,考虑每个修改区间对答案的影响。
注意到我们是先进行一些修改,然后进行一些查询,一共 \(O(\frac{\sqrt{n}}{\ln n})\) 轮。
区间修改区间查询可以使用树状数组的差分方式变成单点修改前缀和。我们考虑使用分块来代替这个树状数组。
考虑块长为 \(B\),每次在块内做后缀和,结束后大块做前缀和,查询 \(O(1)\),复杂度是 \(O(\frac{n^{\frac{3}{4}}}{\ln n}\times B+\frac{n}{B\ln n})\),取 \(B=n^{\frac{1}{8}}\) 可以做到 \(O(\frac{n^{\frac{7}{8}}}{\ln n})\) 的复杂度。怎么这么奇怪啊
这玩意儿当个乐呵就好了。。。。。。下面是正经部分。
考虑怎么通过类似 min25 筛的爆搜去搜这个东西。
每次搜质因子的时候,我们枚举一下这个质因子是否为这个数的次大质因子。如果是,那就在后面跟上一个质数前缀和,否则就接着搜下去。
设 \(f[n]\) 为 \(n\) 以内质数个数,那么这玩意儿看上去是这样的:
#include<cstdio>
typedef unsigned ui;
typedef __uint128_t LL;
typedef unsigned long long ull;
const ui M=1e6+5;
ull l,r;ui g[M];ull f[M];ull B[M];
ui m,top,pri[M];
inline ull DFS(const ull&n,const ui&k,const ull&T){
if(n<=pri[k])return 0;
ull ans(0);
for(ui K=k+1;K<=top&&1ull*pri[K]*pri[K]<=n;++K){
const ui&P=pri[K];const ull&BR=B[P];ull N=LL(n)*BR>>63,M=P;
while(P<=N){
ans+=DFS(N,K,T*M)+P*((N<=m?g[N]:f[T*M])-K+1);
N=LL(N)*BR>>63;M*=P;
}
}
return ans;
}
inline ull Solve(const ull&n){
top=0;m=1;
while(1ull*m*m<=n){
B[m]=((1ull<<63)+m-1)/m;
g[m]=m-1;f[m]=n/m-1;
++m;
}
B[m]=((1ull<<63)+m-1)/m;--m;
for(ui i=2;i<=m;++i)if(g[i]^g[i-1]){
const ull&x=LL(n)*B[i]>>63;const ui&Lim=LL(m)*B[i]>>63,&S=g[i-1];ui lim=m;
if(1ull*lim*i>x)lim=LL(x)*B[i]>>63;
pri[++top]=i;
for(ui j=1;j<=lim;++j){
if(j<=Lim)f[j]-=f[i*j]-S;
else f[j]-=g[LL(x)*B[j]>>63]-S;
}
if(1ull*i*i<=m){
for(ui j=m;j>=i*i;--j){
g[j]-=g[LL(j)*B[i]>>63]-S;
}
}
}
return DFS(n,0,1);
}
signed main(){
scanf("%llu%llu",&l,&r);
printf("%llu",Solve(r)-Solve(l-1));
}