BZOJ4176&&BZOJ3994

BZOJ 4176 http://www.lydsy.com/JudgeOnline/problem.php?id=4176

 莫比乌斯反演+杜教筛

 

 

好像μ可以杜教筛肛

  s可以有√n的做法

复杂度为

 

 

#include<cstdio>
#include<cmath>
#include<map>
typedef long long ll;
std::map<ll,int>m1;
std::map<ll,ll>m2;
std::map<ll,bool>vis1,vis2;
const int N=10000011;
const int mod=1000000007;
bool ip[N];
int pr[N],miu[N];
int pos,blo;
ll ans,n;
inline void shai_fa(){
	miu[1]=1;
	for(register int i=2;i<=blo;++i){
		if(!ip[i])
			miu[pr[++pr[0]]=i]=-1;
		for(register int j=1;j<=pr[0]&&pr[j]*i<=blo;++j){
			ip[i*pr[j]]=1;
			if(i%pr[j]==0)
				break;
			miu[i*pr[j]]=-miu[i];
		}
	}
	for(register int i=1;i<=blo;++i)
		miu[i]=miu[i-1]+miu[i];
}
inline int getmiu(ll x){
	if(x<=blo)return miu[x];
	if(vis1[x])return m1[x];
	int ans=1;
	ll pos;
	for(register ll i=2;i<=x;i=pos+1){
		pos=x/(x/i);
		ans-=(pos-i+1)*getmiu(x/i);
		if(ans<0)
			ans+=mod;
	}
	vis1[x]=1;
	return m1[x]=ans;
}
inline ll getf(ll x){
	if(vis2[x])return m2[x];
	ll ans=0,pos;
	for(register ll i=1;i<=x;i=pos+1){
		pos=x/(x/i);
		ans+=1ll*(pos-i+1)%mod*(x/i);
		ans%=mod;
	}
	vis2[x]=1;
	return m2[x]=1ll*ans*ans%mod;
}
int main(){
	scanf("%lld",&n);
	blo=pow(n,2.00/3.00);
	shai_fa();
	for(register ll i=1,pos;i<=n;i=pos+1){
		pos=n/(n/i);
		ans+=1ll*(getmiu(pos)-getmiu(i-1))*getf(n/i)%mod;
		ans=(ans+mod)%mod; 
	}
	printf("%lld\n",ans);
	return 0;
} 

  

BZOJ3994 http://www.lydsy.com/JudgeOnline/problem.php?id=3994

这只是多了一个打表预处理S(i)的过程

#include<cstdio>
#define FOR(i,s,t) for(register int i=s;i<=t;++i)
inline int min(int a,int b){return a<b?a:b;}
typedef long long ll;
const int N=50011,maxn=50000;
int miu[N],pr[N/12];
ll ans[N];
ll res;
bool ip[N];
int pos;
inline void shai_fa(){
    miu[1]=1;
    for(register int i=2;i<=maxn;++i){
        if(!ip[i])
            miu[pr[++pr[0]]=i]=-1;
        for(register int j=1;j<=pr[0]&&pr[j]*i<=maxn;++j){
            ip[i*pr[j]]=1;
            if(i%pr[j]==0)break;
            miu[i*pr[j]]=-miu[i];	
        }	
    }
    for(register int i=1;i<=maxn;++i)
        miu[i]+=miu[i-1];
}
inline ll getf(int x){
    int pos;
    ll ans=0;
    for(register int i=1;i<=x;i=pos+1){
        pos=x/(x/i);
        ans+=1ll*(pos-i+1)*(x/i);
    }
    return ans;
}
int n,m,T;
int main(){
    shai_fa();
    FOR(i,1,maxn)ans[i]=getf(i);
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        res=0;
        for(register int i=1;i<=min(n,m);i=pos+1){
            pos=min(n/(n/i),m/(m/i));
            res+=1ll*(miu[pos]-miu[i-1])*ans[n/i]*ans[m/i];
        }
        printf("%lld\n",res);
    }
    return 0;
}

  

posted @ 2017-12-15 11:01  Stump  阅读(675)  评论(0编辑  收藏  举报