bzoj 3944 Sum —— 杜教筛

Posted zinn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3944 Sum —— 杜教筛相关的知识,希望对你有一定的参考价值。

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3944

杜教筛入门题!

看博客:https://www.cnblogs.com/zjp-shadow/p/8491542.html

写法模仿其他博客的,但很慢啊...

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
int const maxn=4000005;
ll T,m,p[maxn],phi[maxn],mu[maxn],cnt,mx;
bool vis[maxn];
map<ll,ll>mp1,mp2;
ll rd()
{
    ll ret=0,f=1; char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1; ch=getchar();}
    while(ch>=0&&ch<=9)ret=(ret<<3)+(ret<<1)+ch-0,ch=getchar();
    return ret*f;
}
void init()
{
    int n=mx;
    phi[1]=1; mu[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!vis[i])phi[i]=i-1,p[++cnt]=i,mu[i]=-1,vis[i]=1;
        for(int j=1;j<=cnt&&i*p[j]<=n;j++)
        {
            vis[i*p[j]]=1;
            if(i%p[j]==0)
            {
                phi[i*p[j]]=phi[i]*p[j]; mu[i*p[j]]=0;
                break;
            }
            phi[i*p[j]]=phi[i]*(p[j]-1);
            mu[i*p[j]]=-mu[i];
        }
    }
    for(int i=1;i<=n;i++)mu[i]+=mu[i-1],phi[i]+=phi[i-1];
}
void dfs(ll n,ll &ans1,ll &ans2)
{
    if(n<mx){ans1=phi[n]; ans2=mu[n]; return;}
    if(mp1.count(n)){ans1=mp1[n]; ans2=mp2[n]; return;}
    ans1=(n+1)*n/2; ans2=1;
    for(ll i=2,lst;i<=n;i=lst+1)
    {
        lst=n/(n/i);// i ~ n/(n/i) 答案都相同
        ll tmp1,tmp2; dfs(n/i,tmp1,tmp2);
        ans1-=tmp1*(lst-i+1); 
        ans2-=tmp2*(lst-i+1);
    }
    mp1[n]=ans1; mp2[n]=ans2; 
}
int main()
{
    mx=4000000;
    init();
    T=rd();
    while(T--)
    {
        m=rd();
        ll ans1,ans2; dfs(m,ans1,ans2);
        printf("%lld %lld
",ans1,ans2);
    }
    return 0;
}

 

以上是关于bzoj 3944 Sum —— 杜教筛的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ_3944_Sum_杜教筛

BZOJ.3944.Sum(杜教筛)

●杜教筛入门(BZOJ 3944 Sum)

BZOJ3944/4805Sum/欧拉函数求和 杜教筛

3944: Sum[杜教筛]

3944: Sum(杜教筛)