[51nod][积性函数][杜教筛]最大公约数之和 V3

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1237

sol:

本来已经不想做裸题了,但是之前的题总是要调一下才能过,就很不优美
这题终于一遍过了,感觉差不多把调试的坑点给找完了。

杜教筛的精髓似乎也掌握到一点了。
简单反演

nddndindj(i,j)=1 ∑ d n d ∑ i n d ∑ j n d ( i , j ) = 1
ndd(2(ndjϕ(i))1) ∑ d n d ( 2 ( ∑ j n d ϕ ( i ) ) − 1 )
筛一下phi。这里的phi我已经不是用tangls的那种推导方式了,而是使用了套路的推导方式,感觉确实已经很通用了。

#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;

ll n;

inline int read()
{
    char c;
    bool pd=0;
    while((c=getchar())>'9'||c<'0')
    if(c=='-') pd=1;
    int res=c-'0';
    while((c=getchar())>='0'&&c<='9')
    res=(res<<3)+(res<<1)+c-'0';
    return pd?-res:res;
}
const int N=1e6;
const int pyz=1e9+7;
int inv2;
int phi[N+7],s[N+7];
inline int ksm(int s,int t)
{
    int res=1;
    while(t)
    {
        if(t&1) res=(ll)res*s%pyz;
        s=(ll)s*s%pyz;
        t>>=1;
    }
    return res;
}
inline get_f(ll x)
{
    if(x<=N) return phi[x];
    if(s[n/x]) return s[n/x];
    s[n/x]=(ll)x%pyz*(x%pyz+1)%pyz*inv2%pyz;
    ll a,b;
    for(ll i=2;i<=x;++i)
    {
        a=x/i;
        b=x/a;
        s[n/x]=(s[n/x]-(ll)get_f(a)*((b-i+1)%pyz)%pyz+pyz)%pyz;
        i=b;
    }
    return s[n/x];
}
int prime[N];
bool is[N+7]; 
int main()
{
//  freopen("1237.in","r",stdin);
//  freopen(".out","w",stdout);
    cin>>n;
    inv2=ksm(2,pyz-2);
    ll a,b,ans=0;
    phi[1]=1;
    for(int i=2;i<=N;++i)
    {
        if(!is[i]) prime[++prime[0]]=i,phi[i]=i-1;
        for(int j=1;j<=prime[0]&&i*prime[j]<=N;++j)
        {
            is[i*prime[j]]=1;
            if(!(i%prime[j]))
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
        phi[i]=(phi[i-1]+phi[i])%pyz;
    }
    for(ll i=1;i<=n;++i)
    {
        a=n/i;
        b=n/a;
        ans=(ans+(i+b)%pyz*((b-i+1)%pyz)%pyz*inv2%pyz*(2*get_f(a)%pyz-1)%pyz)%pyz;
        i=b;
    }
    ans=(ans+pyz)%pyz;
    cout<

你可能感兴趣的:(51nod,杜教筛,积性函数)