[HDU5942]Just a Math Problem(莫比乌斯反演)

题面

http://acm.hdu.edu.cn/showproblem.php?pid=5942

题解

前置知识

引理

\[2^{f(n)}={\sum\limits_{d1*d2=n}[(d1,d2)=1]}\]

  • 此处的f(n)即为题目中的f(n)。

证明:设\(n={\prod_{i=1}^{k}}{p_i^{\alpha_i}}\),各\(p_i\)是质数。

\[RHS = {\prod\limits_{i=1}^{k}}{\sum\limits_{\beta_1+\beta_2=\alpha_i}}[min(\beta_1,\beta_2)=0]\]

\[={\prod\limits_{i=1}^{k}}2=2^k=LHS\]
引理得证。

回原题

\[{\sum\limits_{i=1}^{n}}2^{f(i)}\]

\[={\sum\limits_{i=1}^{n}}{\sum\limits_{d1*d2=i}}[(d1,d2)=1]\]

\[={\sum\limits_{d1*d2{\leq}n}}[(d1,d2)=1]\]

\[={\sum\limits_{d1*d2{\leq}n}}{\ }{\sum\limits_{d|(d1,d2)}}{\mu(d)}\]

\[={\sum\limits_{d}}{\mu(d)}{\sum\limits_{d1*d2{\leq}n}}[d|d1][d|d2]\]

\[={\sum\limits_{d}}{\mu(d)}*s({\lfloor}{\frac{n}{d^2}}{\rfloor})\]

\[={\sum\limits_{d{\leq}{\sqrt{n}}}}{\mu(d)}*s({\lfloor}{\frac{n}{d^2}}{\rfloor})\]

其中s(n)表示\({\sum_{i=1}^{n}}{\lfloor}{\frac{n}{i}}{\rfloor}\)。求s(n)是经典的数论分块问题,可以\(O(\sqrt{n})\)解决。

总时间复杂度\(O(T({\sqrt{\frac{n}{1^2}}}+{\sqrt{\frac{n}{2^2}}}+…+{\sqrt{\frac{n}{{\sqrt{n}}^2}}}))\)

\[=O(T{\sqrt{n}}H({\sqrt{n}}))\](H为调和级数)

\[=O(T{\sqrt{n}}logn)\]

  • P.S.此题巨卡无比;需要各种卡常技巧;比如给s加一些记忆化,mu=0时跳过s的计算,以及尽一切可能避免mod等等。

代码

#include<bits/stdc++.h>

using namespace std;

#define sqrtN 1000000
#define rg register
#define ll long long
#define mod 1000000007

const ll T = 20000000;

namespace ModCalc{
    inline void Inc(ll &x,ll y){
        x += y;if(x >= mod)x -= mod;
    }
    
    inline void Dec(ll &x,ll y){
        x -= y;if(x < mod)x += mod;
    }
    
    inline ll Add(ll x,ll y){
        Inc(x,y);return x;
    }
    
    inline ll Sub(ll x,ll y){
        Dec(x,y);return x;
    }
}
using namespace ModCalc;

inline ll read(){
    ll s = 0,ww = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();}
    while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();}
    return s * ww;
}

inline void write(ll x){
    if(x < 0)x = -x,putchar('-');
    if(x > 9)write(x / 10);
    putchar('0' + x % 10);
}

ll pn;
ll pri[sqrtN+5],mu[sqrtN+5];
bool isp[sqrtN+5];
ll S[T+5];

inline void Eular(){
    mu[1] = 1;
    for(rg ll i = 2;i <= sqrtN;i++)isp[i] = 1;
    for(rg ll i = 2;i <= sqrtN;i++){
        if(isp[i])pri[++pn] = i,mu[i] = -1;
        for(rg ll j = 1;i * pri[j] <= sqrtN;j++){
            isp[i*pri[j]] = 0;
            if(i % pri[j])mu[i*pri[j]] = -mu[i];
            else{
                mu[i*pri[j]] = 0;
                break;
            }
        }
    }
}

inline ll s(ll n){
    if(n <= T && S[n])return S[n];
    ll L,R = 0;
    ll ans = 0;
    while(R < n){
        L = R + 1,R = n / (n / L);
        ans = (ans + (R - L + 1) * (n / L)) % mod;
    }
    if(n <= T)S[n] = ans;
    return ans;
}

int main(){
    Eular();
    ll c = 1;
    ll T = read();
    while(T--){
        printf("Case #%lld: ",c++);
        ll n = read();
        ll ans = 0;
        for(rg ll i = 1;i * i <= n;i++)if(mu[i])ans = (ans + mu[i] * s(n/i/i)) % mod;
        write((ans + mod) % mod),putchar('\n');
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xh092113/p/12289949.html