筛子
分块前缀和杜教筛很详细了……
PPT: D:/shr/OI/数论.pdf (雾
powerful number
考虑求一个奇怪积性函数 \(f(x)\) 的前缀和 \(F(x)\) 。
然后想到找一个前缀和好算的积性函数 \(g(x)\) ,使得任意 \(p\) 为素数, \(g(x)=f(x)\) 。
求出积性函数函数 \(h\) 使 \(f=g*h\) ,先求出素数次幂 \(p^k\) 的 \(h\) ,每次复杂度为 \(O(k^2)\) 。
再考虑一下 \(h\) 的性质:
当求质数点值时: \(f(p)=g(p)h(1)+g(1)h(p)\)
由积性函数 \(1\) 处值为 \(1\) 所以 \(h(p)=0\)
再由积性函数性质,所有满足有素因子指数为 \(1\) 的 \(x\) , \(h(x)=0\) 。
剩下所有 \(h(x)\not=0\) 的 \(x\) 都称作 \(\text{powerful number}\) 。
这样的数均可以表示为 \(a^3b^2\) 的形式,有 \(O(\sqrt{n})\) 个。
可以爆搜求出所有 \(\text{powerful number}\) 及其点值。
求 \(F(n)=\sum_{d=1}^{n}h(i)G(\frac{n}{d})\) ,对于所有 \(\text{powerful number}\) 处求值即可。
min_25 筛
求积性函数 \(f(i)\) 的前缀和。我们显然要知道且能够快速算出 \(f(p^k)\) 的值。
先把 \(f(i)\) 手动拆成 \(O(1)\) 个完全积性函数的和或差,后面要用到性质。
令 \(P_j\) 为第 \(j\) 个质数,对每个完全积性函数 \(f'(i)\) 分别求一个 \(g(n,j)=[p\in\mathbb{P}|\min_{i|p}i>P_j]f'(p)\)
本质上是用前 \(j\) 个质数埃氏筛剩下的数 \(f'\) 之和。
DP 求出 \(g\) 的值:
当 \(P_j^2>n\) 时: \(g(n,j)=g(n,j-1)\) ,在 \(j\) 之前所有数都筛完了。
当 \(P^j\le n\) 时: \(g(n,j)=g(n,j-1)-f'(P_j)(g(\frac{n}{P_j},j-1)-\sum_{i=1}^{j-1}f'(P_i))\)
因为 \(f'\) 是个完全积性函数,所以是对的。
有注意到只需要对 \(P_j\ge\sqrt{n}\) 的 \(j\) 进行转移,且 \(\frac{n}{P_j}\) 只会有 \(O(\sqrt{n})\) 个取值,所以这里复杂度还好。
(需要离散化一下 \(\frac{n}{P_j}\) ,注意 DP 的时候对于每个 \(n\) 只需要一个变量,能直接从 \(j-1\) 继承, 保证 \(\frac{n}{P_j}\) 会比 \(n\) 后更新,即从大到小做即可)
此时已经求出了一个东西:\(g(n,|\mathbb{P}|)\) ,\(f'\) 在质数处的前缀和。
考虑求出所有数的前缀和,设 \(s(n,j)=[\min_{i|p}i>P_j]f(p)\) ,注意此时求的是积性函数 \(f\) 的了,不是 \(f'\) 的。
答案就是 \(s(n,0)\) 。
这样设,按照 \(s\) 的定义,可以满足积性函数的性质来进行转移(这之后只会从 \(j\) 更大的 \(S\) 来转移过来,不会和因子 \(P_j\) 有重叠)。
意为所有质数减去 \(P_j\) 以内质数的贡献,加上合数的贡献。
\([e>1]\) 是因为当 \(e=1\) 时,为质数,在最前面已经加上贡献了。
同样只需要 \(P_j\le\sqrt{n}\) 的,且 \(n\) 只用 \(O(\sqrt{n})\) 个取值。
不过注意到上面所有讨论都对 \(1\) 是无效的,所以前面应减掉 \(1\) 的贡献,最后答案为 \(s(n,0)+1\) 。
Luogu5325 代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+7,mod=1e9+7;
ll n,c[N];
int m,sz,s,b[N],p[N],s1[N],s2[N],g1[N],g2[N],id1[N],id2[N];
int gt(ll x) {return x<=m?id1[x]:id2[n/x];}
ll f1(ll x) {x%=mod;return x*(x+1)/2%mod;}
ll f2(ll x) {x%=mod;return x*(x+1)%mod*(x*2+1)%mod*166666668%mod;}
int solve(ll x,int j){
if(p[j]>x) return 0;
int res=((g2[gt(x)]-g1[gt(x)]-s2[j]+s1[j])%mod+mod)%mod;
for(int i=j+1;i<=sz&&1ll*p[i]*p[i]<=x;i++)
for(ll e=1,ml=p[i];ml<=x;ml*=p[i],e++) (res+=ml%mod*(ml%mod-1)%mod*(solve(x/ml,i)+(e>1))%mod)%=mod;
return res;
}
signed main(){
scanf("%lld",&n);m=sqrt(n);
for(int i=2;i<=m;i++){
if(!b[i]) p[++sz]=i;
for(int j=1;i*p[j]<=m&&j<=sz;j++){
b[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
for(int i=1;i<=sz;i++) s1[i]=(s1[i-1]+p[i])%mod,s2[i]=(s2[i-1]+1ll*p[i]*p[i]%mod)%mod;
for(ll l=1,r;l<=n;l=r+1){
r=n/(c[++s]=n/l);
g1[s]=f1(c[s])-1;g2[s]=f2(c[s])-1;
if(c[s]<=m) id1[c[s]]=s;else id2[n/c[s]]=s;
}
for(int i=1;i<=sz;i++)
for(int j=1;j<=s&&1ll*p[i]*p[i]<=c[j];j++){
g1[j]=(g1[j]-1ll*p[i]*(g1[gt(c[j]/p[i])]-s1[i-1])%mod+mod)%mod;
g2[j]=(g2[j]-1ll*p[i]*p[i]%mod*(g2[gt(c[j]/p[i])]-s2[i-1])%mod+mod)%mod;
}
printf("%d\n",(solve(n,0)+1)%mod);
return 0;
}
为啥我一会叫素数一会叫质数!!!

浙公网安备 33010602011771号