【杜教筛】学习笔记

思路

普通杜教筛

扩展杜教筛

代码

普通杜教筛(BZOJ3944 sum)

//by 减维
#include<set>
#include<map>
#include<queue>
#include<ctime>
#include<cmath>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define il inline
#define rg register
#define db double
#define mpr make_pair
#define maxn 5000005
#define inf (1<<30)
#define eps 1e-8
#define pi 3.1415926535897932384626L
using namespace std;

inline int read()
{
    int ret=0;bool fla=0;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-'){fla=1;ch=getchar();}
    while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();}
    return fla?-ret:ret;
}

ll t,n,tot,pri[maxn/10],phi[maxn],mu[maxn],q[maxn/10],p[maxn/10];
bool pd[maxn],vis[maxn];

void pre(ll x)
{
    pd[1]=1;phi[1]=1;mu[1]=1;
    for(rg ll i=2;i<=x;++i)
    {
        if(!pd[i]) pri[++tot]=i,phi[i]=i-1,mu[i]=-1;
        for(rg int j=1;j<=tot&&i*pri[j]<=x;++j)
        {
            pd[pri[j]*i]=1;
            if(i%pri[j]==0)
            {
                phi[i*pri[j]]=phi[i]*pri[j];
                mu[i*pri[j]]=0;
                break ;
            }
            phi[i*pri[j]]=phi[i]*phi[pri[j]];
            mu[i*pri[j]]=-mu[i];
        }
    }
    for(rg int i=2;i<=x;++i) phi[i]+=phi[i-1],mu[i]+=mu[i-1];
}

il ll getp(ll x){return x<=maxn-5?phi[x]:p[n/x];}
il ll getq(ll x){return x<=maxn-5?mu[x]:q[n/x];}

void solve(ll x)
{
    if(x<=5000000) return ;
    if(vis[n/x]) return ;
    vis[n/x]=1;
    p[n/x]=x*(x+1)/2;
    q[n/x]=1;
    for(rg ll i=2,las;i<=x;i=las+1)
    {
        las=x/(x/i);solve(x/i);
        p[n/x]-=(las-i+1)*getp(x/i);
        q[n/x]-=(las-i+1)*getq(x/i);
    }
}

int main()
{
    scanf("%lld",&t);
    pre(5000000);
    while(t--)
    {
        scanf("%lld",&n);
        memset(vis,0,sizeof vis);
        solve(n);
        printf("%lld %lld\n",getp(n),getq(n));
    }
    return 0;
}

扩展杜教筛(51nod1237 最小公倍数之和 V3)

//by 减维
#include<set>
#include<map>
#include<queue>
#include<ctime>
#include<cmath>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define il inline
#define rg register
#define db double
#define mpr make_pair
#define maxn 5000005
#define inf (1<<30)
#define eps 1e-8
#define pi 3.1415926535897932384626L
#define mod 1000000007
using namespace std;

inline int read()
{
    int ret=0;bool fla=0;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-'){fla=1;ch=getchar();}
    while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();}
    return fla?-ret:ret;
}
ll n,p,tot,inv2,inv6,pri[maxn],phi[maxn];
bool pd[maxn];
map<ll,ll> mp;

ll ksm(ll x,ll y)
{
    ll ret=1;
    while(y)
    {
        if(y&1) ret=ret*x%p;
        x=x*x%p;
        y>>=1;
    }
    return ret;
}

void pre(ll x)
{
    phi[1]=1;
    for(ll i=2;i<=x;++i)
    {
        if(!pd[i]) pri[++tot]=i,phi[i]=(i-1)%p;
        for(int j=1;j<=tot&&i*pri[j]<=x;++j)
        {
            pd[i*pri[j]]=1;
            if(i%pri[j]==0)
            {
                phi[i*pri[j]]=(phi[i]*pri[j])%p;
                break ;
            }
            phi[i*pri[j]]=(phi[i]*phi[pri[j]])%p;
        }
    }
    for(ll i=1;i<=x;++i) phi[i]=phi[i]*i%p*i%p;
    for(ll i=1;i<=x;++i) phi[i]=(phi[i]+phi[i-1])%p;
    inv2=ksm(2,p-2);
    inv6=ksm(6,p-2);
}

ll f(ll x)
{
    return ((x%p)*((x+1)%p)%p*inv2%p)*((x%p)*((x+1)%p)%p*inv2%p)%p;
}

ll ff(ll x)
{
    return (x%p)*((x+1)%p)%p*inv2%p;
}

ll pf(ll x)
{
    return (x%p)*((x%p+1)%p)%p*((2*x%p+1)%p)%p*inv6%p;
}

ll getji(ll x)
{
    if(x<=maxn-5) return phi[x];
    if(mp[x]) return mp[x];
    ll ret=f(x);
    for(ll l=2,r;l<=x;l=r+1)
    {
        r=x/(x/l);
        ret-=(pf(r)%p-pf(l-1)%p+p)%p*getji(x/l)%p;
        ret%=p;ret+=p;ret%=p;
    }
    return mp[x]=ret;
}

ll solve()
{
    ll ret=0;
    for(ll l=1,r;l<=n;l=r+1)
    {
        r=n/(n/l);
        ret+=ff(n/l)*((getji(r)-getji(l-1)+p)%p)%p;
        ret%=p;
    }
    return ret;
}

int main()
{
    scanf("%lld",&n);p=1000000007;
    pre(maxn-5);
    printf("%lld",solve());
    return 0;
}
posted @ 2018-01-25 15:27  减维  阅读(272)  评论(0编辑  收藏  举报