• Min_25筛学习小计


    好菜啊,现在才会Min_25

    简单介绍

    • 由Min_25在他的博客中介绍的做法,又称Min_25筛。
    • 用于求积性函数f(n)f(n)的前缀和,其中要求f(p)f(p)可以表示成多项式,并且f(pk)f(p^k)可以快速算出。
    • 能够在O(n0.75log)O(frac{n^{0.75}}{log})的时间内算出。

    基本思路

    • 使用DPDP先求出所有素数的f(p)f(p)的前缀和,然后再通过枚举最小的质因子计算出合数的前缀和。

    求素数的前缀和

    • 下面的所有除法都为整除。
    • 我们之后要求对所有的m=nim=frac{n}{i}iprime,i<=mf(i)sum_{isubseteq prime,i<=m}f(i)
    • 为了方便计算我们将f(i)f(i)拆成几个完全积性函数的和。使得这些积性函数在素数pp的位置的和与f(i)f(i)一致。
    • 接下来考虑一个完全积性函数f(i)f(i)在素数位置的和怎么求。
    • 那么用容斥,考虑用所有的和减去合数的和。
    • g(n,j)=i=1n[iprimeminp(i)>pri[j]]f(i)g(n,j)=sum_{i=1}^n[isubseteq prime|minp(i)>pri[j]]f(i)
    • g(n,j)g(n,j)g(n,j+1)g(n,j+1)的过程相当于是一个埃氏筛法(即找出nsqrt n下的质数,将它的倍数筛掉,相当于现在筛到的数的最小因子为当前质数)。
    • 那么如果pri[j]2>npri[j]^2>n,则pri[j]pri[j]不能继续筛了,所以:
      g(n,j)=g(n,j1)g(n,j)=g(n,j-1)
    • 否则pri[j]pri[j]可以筛,即为:
      g(n,j)=g(n,j1)pri[j](g(n/pri[j],j1)k<jf(pri[k]))g(n,j)=g(n,j-1)-pri[j](g(n/pri[j],j-1)-sum_{k<j}f(pri[k]))
    • 因为gg里面有小于pri[j]pri[j]的质数,但是它们乘上pri[j]pri[j]的最小因子并不是pri[j]pri[j],不满足当前筛的数的范围——最小质因子为pri[j]pri[j],所以减去。
    • 最后求得g(n,P)g(n,|P|)即为素数的和了。

    亿点点细节

    • 一般使用pkp^k作为完全积性函数,初值g(n,0)g(n,0)就是一个自然数幂求和。
    • 这个东西用滚动数组求。
    • 由于要求所有g(ni,P)g(frac{n}{i},|P|),查找的时候可以设一个id1,id2id1,id2,如果i<=sqrt(n)i<=sqrt(n)就直接存在该位置,否则存在n/in/i的位置,可以证明一一对应。然后离散化去储存和转移。
    • 还需要在线筛时预先求出k<jf(pri[k])sum_{k<j}f(pri[k])
    • 至此我们就能求出i<=mf(i)sum_{i<=m}f(i),这里的f(i)f(i)是题意中的函数。
    • 所有计算都不计算1的贡献,因为筛的时候比较方便

    求所有数的前缀和

    • S(n,j)=i=1n[minp(i)>=pri[j]]f(i)S(n,j)=sum_{i=1}^n[minp(i)>=pri[j]]f(i)
    • S(n,j)=g(n,P)k<jf(pri[k])+k=jpri[k]2<=nq=1pri[k]q+1<=nS(n/pri[k]q,k+1)+f(pri[k]q+1)S(n,j)=g(n,|P|)-sum_{k<j}f(pri[k])+sum_{k=j}^{pri[k]^2<=n}sum_{q=1}^{pri[k]^{q+1}<=n}S(n/pri[k]^q,k+1)+f(pri[k]^{q+1})
    • 前面的质数的和,后面合数的和也是枚举最小的质因子的次幂去筛它,注意最后一项算不到要补上。
    • 出口即n<pri[j],n=1n<pri[j],n=1返回00
    • 因为整除的数是有限且不重复的,所以S(n,j)S(n,j)并不需要像杜教筛一样记忆化。
    • 听说时间是O(n0.75log)O(frac{n^{0.75}}{log})的,最快能过101210^{12}
    • 相较杜教筛普适性更高了,但是速度也更慢了。
      luoguP3235
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define maxn 500005
    #define ll long long 
    #define mo 1000000007
    using namespace std;
    
    ll n,sqr,i,j,k,m,inv6;
    ll id1[maxn],id2[maxn],w[maxn];
    ll bz[maxn],tot,pri[maxn],sg1[maxn],sg2[maxn];
    ll s[maxn],g1[maxn],g2[maxn];
    
    ll ksm(ll x,ll y){
    	ll s=1;
    	for(;y;y/=2,x=x*x%mo) if (y&1)
    		s=s*x%mo;
    	return s;
    }
    
    void getpri(){
    	for(i=2;i<=sqr;i++){
    		if (!bz[i]) {
    			pri[++tot]=i;
    			sg1[tot]=(sg1[tot-1]+i)%mo;
    			sg2[tot]=(sg2[tot-1]+1ll*i*i)%mo;
    		}
    		for(j=1;j<=tot&&i*pri[j]<=sqr;j++){
    			bz[i*pri[j]]=1;
    			if (i%pri[j]==0) break;
    		}
    	}
    }
    
    void prepare(){
    	getpri();
    	for(i=1;i<=n;i=j+1){
    		j=n/(n/i),w[++m]=n/i;
    		if (w[m]<=sqr) id1[w[m]]=m; else
    			id2[n/w[m]]=m;
    		ll tmp=w[m]%mo; 
    		g1[m]=(tmp+1)*tmp/2%mo-1;
    		g2[m]=tmp*(tmp+1)%mo*(tmp*2+1)%mo*inv6%mo-1;
    	}
    	for(j=1;j<=tot;j++){
    		for(i=1;i<=m&&pri[j]*pri[j]<=w[i];i++){
    			int k=(w[i]/pri[j]<=sqr)?id1[w[i]/pri[j]]:id2[n/(w[i]/pri[j])];	
    			(g1[i]-=pri[j]*(g1[k]-sg1[j-1]))%=mo;
    			(g2[i]-=pri[j]*pri[j]%mo*(g2[k]-sg2[j-1]))%=mo;
    		}
    	}
    }
    
    ll S(ll x,int j){
    	if (x==1||pri[j]>x) return 0;
    	int k=(x<=sqr)?id1[x]:id2[n/x];
    	ll sum=g2[k]-g1[k]-sg2[j-1]+sg1[j-1];
    	for(k=j;k<=tot&&pri[k]*pri[k]<=x;k++){
    		ll p=pri[k],q=p%mo;
    		while (p*pri[k]<=x){
    			sum+=S(x/p,k+1)*(q*(q-1)%mo)%mo;
    			p=p*pri[k],q=q*pri[k]%mo,sum+=q*(q-1)%mo;
    		}
    	}
    	return sum%mo;
    }
    
    int main(){
    	scanf("%lld",&n),sqr=sqrt(n),inv6=ksm(6,mo-2);
    	prepare();
    	printf("%lld",S(n,1)+1);
    }
    
    
  • 相关阅读:
    大学的最后时光---我的毕设日记(二)
    大学的最后时光---我的毕设日记(一)
    记公司同事的一次集体活动
    ssh框架基本原理
    plsql基本操作记录
    eclipse快捷键。
    面向对象的特性:封装继承多态
    设置label中的对齐方式
    pixmap和label设置图片自适应大小
    类的继承
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/13090876.html
Copyright © 2020-2023  润新知