莫比乌斯反演学习之路~

首先是线性筛

由于每一个数只会被筛一次,所以复杂度为on
筛mobius函数

void init()
{
    memset(book,0,sizeof(book));
    memset(mu,0,sizeof(mu));
    memset(prime,0,sizeof(prime));
    mu[1]=1;cnt=0;
    for(int i=2;i<=n;i++)
    {
        if(!book[i])
            prime[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&prime[j]*i<=n;j++)
        {
            book[i*prime[j]]=1;
            if(i%prime[j]) mu[i*prime[j]]=-mu[i];//如果不整除
            else//否则就跳出
            {
                mu[i*prime[j]]=0;
                break;
            }
        }
    }
}

hdu 1695 无优化

#pragma GCC optimize("O2")
#include
#include
#define maxn 100100
#define int long long
using namespace std;
int cnt,a,b,c,d,k,ans1,ans2,mu[maxn],prime[maxn],book[maxn],t;
void init()
{
    mu[1]=1,cnt=0;
    for(int i=2;i<=maxn;i++)
    {
        if(!book[i]) prime[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&prime[j]*i<=maxn;j++)
        {
            book[i*prime[j]]=1;
            if(i%prime[j]) mu[i*prime[j]]=-mu[i];
            else
            {
                mu[i*prime[j]]=0;
                break;
            }
        }
    }
}

main()
{
    init();
    scanf("%lld",&t);
    for(int kase=0;t;t--)
    {
        scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&k);
        if(k==0){ printf("Case %lld: 0\n",++kase);continue;}
        ans1=ans2=0;
        d/=k,b/=k;
        for(int i=1;i<=min(b,d);i++)
            ans1+=mu[i/1]*(d/i)*(b/i);
        for(int i=1;i<=min(b,d);i++)
            ans2+=mu[i/1]*(min(b,d)/i)*(min(b,d)/i);
        printf("Case %lld: %lld\n",++kase,ans1-ans2/2);
    }
    return 0;
}

BZOJ2301

#pragma GCC optimize("O2")
#include
#include
#define maxn 60100
using namespace std;
int cnt,a,b,c,d,k,ans1,ans2,mu[maxn],prime[maxn],book[maxn],t,sum[maxn];

template<typename tp>void read(tp & dig)
{
    char c=getchar();dig=0;
    while(!isdigit(c))c=getchar();
    while(isdigit(c))dig=dig*10+c-'0',c=getchar();
}

inline void init()
{
    mu[1]=sum[1]=1,cnt=0;
    for(int i=2;i<=maxn;i++)
    {
        if(!book[i]) prime[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&prime[j]*i<=maxn;j++)
        {
            book[i*prime[j]]=1;
            if(i%prime[j]) mu[i*prime[j]]=-mu[i];
            else
            {
                mu[i*prime[j]]=0;
                break;
            }
        }
        sum[i]=sum[i-1]+mu[i];
    }
}
inline int calc(int l,int r)
{
    if(l>r) swap(l,r);
    int ans=0;
    for(int i=1,last=0;i<=l;i=last+1)
    {
        last=min(l/(l/i),r/(r/i));//move to the next equal to the val 
        ans+=(sum[last]-sum[i-1])*(l/i)*(r/i);
    }
    return ans;
}

main()
{
    init();
    read(t);
    for(;t;t--)
    {
        read(a),read(b),read(c),read(d),read(k);
        int ans=calc(b/k,d/k)-calc((a-1)/k,d/k)-calc(b/k,(c-1)/k)+calc((a-1)/k,(c-1)/k);
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(莫比乌斯反演学习之路~)