A:如来神掌!
B:min_25筛~
A:且慢,我投降。
解决一些较为普遍类型的积性函数的求和问题, ∑ i = 1 n f ( i ) \sum_{i=1}^{n}f(i) ∑i=1nf(i)或者 ∑ p ∈ [ 1 , n ] f ( p ) \sum_{p\in[1,n]}f(p) ∑p∈[1,n]f(p),可以用 m i n _ 25 min\_25 min_25筛的前提是:可以在过程中快速求解 f ( p k ) f(p^k) f(pk)。时间复杂度为 O ( n 3 4 l o g n ) O(\frac{n^{\frac{3}{4}}}{logn}) O(lognn43),一般的题 n n n为 1 e 10 1e10 1e10。
已是最佳观影顺序,从上往下看应该就能看懂了。
下文中的 p p p指质数, p i p_i pi指第 i i i个质数, m i n ( i ) min(i) min(i)代表 i i i的最小质因子, ∣ P ∣ |P| ∣P∣表示 [ 1 , n ] [1,\sqrt n] [1,n]内的因子数量。
定义:
定义 g ( x , j ) g(x,j) g(x,j)为: [ 1 , x ] [1,x] [1,x]中的质数的函数值之和,加上最小质因子大于 p j p_j pj的数的函数值之和。后半部分也就是筛掉前面 j j j个素数的因子后的那些合数。
g ( x , j ) = ∑ p ∈ [ 1 , x ] f ( p ) + ∑ i ∈ [ 1 , x ] , m i n ( i ) > p j f ( i ) g(x,j)=\sum_{p\in[1,x]}f(p)+\sum_{i\in[1,x],min(i)>p_j}f(i) g(x,j)=p∈[1,x]∑f(p)+i∈[1,x],min(i)>pj∑f(i)
使用原因:
我们可以快速求出 f ( p c ) f(p^c) f(pc),但是其他合数我们并不能快速得出,所以先将其它的合数套用 f ( p ) f(p) f(p)的式子,然后再逐步删掉。剩下的就是正确的质数部分了。
理论:
当 p j 2 > x p_j^2>x pj2>x时,显然合数的部分不会发生变化,所以此时 g ( x , j ) = g ( x , j − 1 ) g(x,j)=g(x,j-1) g(x,j)=g(x,j−1);
当 p j 2 ≤ x p_j^2\leq x pj2≤x时,我们考虑减去筛掉的合数部分。
显然这些合数,除上一个 p j p_j pj后,省下部分的最小质因子 ≥ p j \geq p_j ≥pj,所以是剩下部分的 ∑ f = g ( x p j , j − 1 ) − ∑ i = 1 j − 1 f ( p i ) \sum_f=g(\frac{x}{p_j},j-1)-\sum_{i=1}^{j-1}f(p_i) ∑f=g(pjx,j−1)−∑i=1j−1f(pi)( g g g里面多包含了小于 p j p_j pj的质数)
所以当 p j 2 ≤ x p_j^2\leq x pj2≤x时, g ( x , j ) = g ( x , j − 1 ) − f ( p j ) ∗ [ g ( x p j , j − 1 ) − ∑ i = 1 j − 1 f ( p i ) ] g(x,j)=g(x,j-1)-f(p_j)*[g(\frac{x}{p_j},j-1)-\sum_{i=1}^{j-1}f(p_i)] g(x,j)=g(x,j−1)−f(pj)∗[g(pjx,j−1)−∑i=1j−1f(pi)]
当 j = 0 j=0 j=0时,根据定义, g ( x , 0 ) = ∑ i = 2 x f ( i ) g(x,0)=\sum_{i=2}^xf(i) g(x,0)=∑i=2xf(i)
运用:
在接下来的运算中,我们需要用到的是 g ( n i , ∣ P ∣ ) g(\frac{n}{i},|P|) g(in,∣P∣),我们预处理这个东西。
g ( x , j ) g(x,j) g(x,j)可以从 g ( x , j − 1 ) g(x,j-1) g(x,j−1)转移,所以我们可以用滚动数组省去第二维。第一维 O ( n ) O(n) O(n)开不下,但是我们可以类似离散化,先预存储下所有可能的 n i \frac{n}{i} in。( n i ≤ n \frac{n}{i}\leq \sqrt n in≤n的一个数组, n i > n \frac{n}{i}> \sqrt n in>n的另外一个)
如果说你求解的是 ∑ p ∈ [ 1 , n ] f ( p ) \sum_{p\in[1,n]}f(p) ∑p∈[1,n]f(p),那么恭喜你,结束了,答案就是 g ( n , ∣ P ∣ ) g(n,|P|) g(n,∣P∣)。
定义:
S ( x , j ) S(x,j) S(x,j)是所有满足最小质因子 ≥ p j \geq p_j ≥pj的函数值之和,最后的答案就是 S ( n , 1 ) + f ( 1 ) S(n,1)+f(1) S(n,1)+f(1)
理论:
指数部分的答案为: g ( x , ∣ P ∣ ) − ∑ i = 1 j − 1 f ( p i ) g(x,|P|)-\sum_{i=1}^{j-1}f(p_i) g(x,∣P∣)−∑i=1j−1f(pi),来考虑合数的部分。
我们可以枚举这些合数的最小质因子 p i p_i pi,已经它的次数 e e e,然后递归处理除上 p i e p_i^e pie后的部分。
S ( x , j ) = g ( x , ∣ P ∣ ) − ∑ i = 1 j − 1 f ( p i ) + ∑ i ∈ [ 1 , ∣ P ∣ ] p i 2 ≤ x ∑ e = 1 p i e + 1 ≤ x S ( x p i e , i + 1 ) ∗ f ( p i e ) + f ( p k e + 1 ) S(x,j)=g(x,|P|)-\sum_{i=1}^{j-1}f(p_i)+\sum_{i\in[1,|P|]}^{p_i^2\leq x}\sum_{e=1}^{p_i^{e+1}\leq x}S(\dfrac{x}{p_i^e},i+1)*f(p_i^e)+f(p_k^{e+1}) S(x,j)=g(x,∣P∣)−i=1∑j−1f(pi)+i∈[1,∣P∣]∑pi2≤xe=1∑pie+1≤xS(piex,i+1)∗f(pie)+f(pke+1)
original link - https://loj.ac/problem/6053
在 p > 2 p>2 p>2时, f ( p ) = p − 1 f(p)=p-1 f(p)=p−1,所以我们分别求 f ( p ) = p f(p)=p f(p)=p和 f ( p ) = 1 f(p)=1 f(p)=1的 g g g函数值,最后带入 S S S求解即可。
只有当 S ( x , 1 ) S(x,1) S(x,1)时才会带上 2 2 2,那个时候加上2即可。
代码:
/*
* Author : Jk_Chen
* Date : 2019-09-27-11.16.23
*/
#include
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair
#define fi first
#define se second
#define debug(x) cerr<<#x<<" = "<
const LL mod=1e9+7;
const int maxn=2e5+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
/*_________________________________________________________begin*/
LL Pow(LL a,LL b,LL mod){
if(a>=mod)a%=mod;
LL res=1;
while(b>0){
if(b&1)res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
/*_________________________________________________________Pow*/
void Add(LL &a,LL b){a=(a%mod+b%mod);while(a>mod)a-=mod; while(a<0)a+=mod;}
LL inv2=Pow(2,mod-2,mod),inv3=Pow(3,mod-2,mod);
bool vis[maxn];
LL pri[maxn],now;
LL sum[maxn];
void init(int n){// 素数筛
rep(i,2,n){
if(!vis[i])pri[++now]=i,sum[now]=(sum[now-1]+i)%mod;
for(int j=1;j<=now&&1ll*pri[j]*i<=n;j++){
vis[pri[j]*i]=1;
if(i%pri[j]==0)break;
}
}
}
LL n,sqr;
LL val[maxn],idx1[maxn],idx2[maxn],ct;// 离散化
LL g0[maxn],g1[maxn];// g函数值
LL S(LL x,LL j){
if(x<=1||pri[j]>x)return 0;
int k = (x<=sqr ? idx1[x] : idx2[n/x]);
LL res=0;
Add(res,g1[k]-g0[k]-(sum[j-1]-(j-1)));
if(j==1)res+=2;
rep(i,j,now){
if(pri[i]*pri[i]>x)break;
LL now=pri[i],nex=pri[i]*pri[i];
rep(e,1,100){
if(nex>x)break;
Add(res,S(x/now,i+1)*(pri[i]^e)%mod+(pri[i]^(e+1)));
now=nex,nex*=pri[i];
}
}
return res;
}
int main(){
n=rd();
sqr=sqrt(1.0*n);
init(sqr);
// n/i 进行分段
for(LL l=1,r;l<=n;l=r+1){
r=n/(n/l);
val[++ct]=n/l;
n/l<=sqr ? idx1[n/l]=ct : idx2[n/(n/l)]=ct;
// 初始化g(x,0) x=val[ct]
// f(p)=1 , 1+1+...1
g0[ct]=val[ct]-1;
// f(p)=i , 2+3+...val[ct]
g1[ct]=(2+val[ct])%mod*((val[ct]-1)%mod)%mod*inv2%mod; // 注意1e10*1e10
}
// 预处理 g(n/x,|P|) |P|=now
rep(j,1,now){ //g(val[i],j)
rep(i,1,ct){
if(pri[j]*pri[j]>val[i])break; // g(x,j)=g(x,j-1)
int k = // idx(val[i]/Pj)
val[i]/pri[j]<=sqr ? idx1[val[i]/pri[j]] : idx2[n/(val[i]/pri[j])];
Add(g0[i],-(g0[k]-(j-1)));
Add(g1[i],-pri[j]*(g1[k]-sum[j-1])%mod);
}
}
printf("%lld\n",S(n,1)+1);
return 0;
}
/*_________________________________________________________end*/
https://www.mina.moe/archives/12287
https://www.cnblogs.com/zhoushuyu/p/9187319.html