# 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

#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  阅读(623)  评论(0编辑  收藏  举报