1. 程式人生 > 實用技巧 >[學習筆記][SDOI2015]約數個數和

[學習筆記][SDOI2015]約數個數和

題目

傳送門

嘗試與思考

\[\sum_{i=1}^n\sum_{j=1}^md(ij) \]

考慮設 \(T=ij\),那麼就有

\[\text{ans}\;=\;\sum_{T=1}^{nm}d(T)\sum_{i=1}^{\frac{T}{m}\le i\le n}[i|T] \]

然後,發現這個東西不可做了,這方法破產了...

考慮另外一種思路,由於我們有

\[d(ij)=\sum_{x|i}\sum_{y|j}[\gcd(x,y)=1] \]

那麼這個式子就是

\[\begin{aligned} \text{ans}\;&=\;\sum_{i=1}^n\sum_{j=1}^m\sum_{x|i}\sum_{y|j}[\gcd(x,y)=1] \\ &=\;\sum_{x=1}^n\sum_{y=1}^m[\gcd(x,y)=1]\sum_{x|i}\sum_{y|j}1 \\ &=\;\sum_{x=1}^n\sum_{y=1}^m[\gcd(x,y)=1]\left\lfloor\frac{n}{x}\right\rfloor\left\lfloor\frac{m}{y}\right\rfloor \\ &=\;\sum_{i=1}^n\sum_{j=1}^m\left\lfloor\frac{n}{i}\right\rfloor\left\lfloor\frac{m}{j}\right\rfloor\sum_{x|i,x|j}\mu(x) \\ &=\;\sum_{x=1}^n\mu(x)\sum_{i=1}^{n/x}\sum_{j=1}^{m/x}\left\lfloor\frac{n}{ix}\right\rfloor\left\lfloor\frac{m}{jx}\right\rfloor \end{aligned} \]

我們令 \(G(T)=\sum_{i=1}^{T}\left\lfloor\frac{T}{i}\right\rfloor\),首先這個函式可以分塊算,同時有

\[\begin{aligned} \text{ans}\;=\;\sum_{x=1}^n\mu(x) G(\left\lfloor\frac{n}{x}\right\rfloor)G(\left\lfloor\frac{m}{x}\right\rfloor) \end{aligned} \]

考慮將 \(G()\) 預處理出來,對於答案也分塊算,那麼總複雜度就是 \(\mathcal O(n\sqrt n+T\sqrt n)\).

程式碼

# include <cstdio>
# include <algorithm>
using namespace std;
namespace Elaina{
    # define rep(i,l,r) for(int i=l, i##_end_ = r; i <= i##_end_; ++ i)
    # define fep(i,l,r) for(int i=l, i##_end_ = r; i >= i##_end_; -- i)
    # define fi first
    # define se second
    # define Endl putchar('\n')
    # define writc(x, c) fwrit(x), putchar(c)
    // # define int long long
    typedef long long ll;
    typedef pair<int, int> pii;
    typedef unsigned long long ull;
    typedef unsigned int uint;
    template<class T>inline T Max(const T x, const T y){return x < y ? y : x;}
    template<class T>inline T Min(const T x, const T y){return x < y ? x : y;}
    template<class T>inline T fab(const T x){return x < 0 ? -x : x;}
    template<class T>inline void getMax(T& x, const T y){x = Max(x, y);}
    template<class T>inline void getMin(T& x, const T y){x = Min(x, y);}
    template<class T>T gcd(const T x, const T y){return y ? gcd(y, x % y) : x;}
    template<class T>inline T readin(T x){
        x=0; int f = 0; char c;
        while((c = getchar()) < '0' || '9' < c) if(c == '-') f = 1;
        for(x = (c ^ 48); '0' <= (c = getchar()) && c <= '9'; x = (x << 1) + (x << 3) + (c ^ 48));
        return f ? -x : x;
    }
    template<class T>void fwrit(const T x){
        if(x < 0)return putchar('-'), fwrit(-x);
        if(x > 9)fwrit(x / 10); putchar(x % 10 ^ 48);
    }
}
using namespace Elaina;

const int maxn = 50000;

int prime[maxn + 5], pcnt;
int sie[maxn + 5], mu[maxn + 5];
ll pre[maxn + 5];
inline void sieve(){
    mu[1] = pre[1] = 1;
    rep(i, 2, maxn){
        if(!sie[i]) prime[++ pcnt] = i, mu[i] = -1;
        for(int j = 1; j <= pcnt && i * prime[j] <= maxn; ++ j){
            sie[i * prime[j]] = 1;
            if(i % prime[j] == 0){
                mu[i * prime[j]] = 0; break;
            }
            mu[i * prime[j]] = -mu[i];
        }
        pre[i] = pre[i - 1] + mu[i];
    }
}

ll G[maxn + 5];

inline ll g(const int n){
    ll ret = 0;
    for(int l = 1, r; l <= n; l = r + 1){
        r = n / (n / l);
        ret += (r - l + 1) * (n / l);
    }
    return ret;
}

int n, m;

signed main(){
    sieve();
    rep(i, 1, maxn) G[i] = g(i);
    rep(cas, 1, readin(1)){
        n = readin(1), m = readin(1);
        if(n > m) swap(n, m);
        ll ans = 0;
        for(int l = 1, r; l <= n; l = r + 1){
            r = Min(n / (n / l), m / (m / l));
            ans += 1ll * (pre[r] - pre[l - 1]) * G[n / l] * G[m / l];
        }
        writc(ans, '\n');
    }
	return 0;
}

用到の一些trick

首當其衝的是這個結論

\[d(ij)=\sum_{x|i}\sum_{y|j}[\gcd(x,y)=1] \]

考慮怎麼證明呢?我們設對於質數 \(p\)\(i\)\(a\) 個,\(j\)\(b\) 個,那麼顯然的,\(ij\) 就有 \(a+b\) 個,同時,在因子的選擇上,\(ij\) 就有 \(a+b+1\) 中選擇方案,而如果我們要保證 \(\gcd(x,y)=1\),那麼對於 \(x,y\) 來說,最多隻有一邊會有 \(p\) 這個因子,那麼對於只有 \(x\) 有的情況來說,有 \(a+1\) 種,對於只有 \(y\) 有的情況,就是 \(b+1\),同時還要減去重複算的兩邊都沒有選擇 \(x\) 的一種,就是 \(a+b+1+1-1=a+b+1\),所以這個可以等價.


其次,是 \(\gcd(x,y)=1\Leftrightarrow\sum_{i|x,i|y}\mu(i)=1\)

其實就是

\[\sum_{d|n}\mu(d)= \begin{cases} 1,n=1 \\ 0,n>1 \end{cases} \]

如果 \(n=1\),那麼顯然.

考慮對於其他情況,設 \(n=p_1^{a_1}..p_k^{a_k}\),那麼在 \(n\) 的所有因子中,\(\mu\) 值不為零的只有所有質因子次數都為 \(1\) 的因子,其中質因數個數為 \(r\) 個的因子有 \({k\choose r}\) 個,那麼就有

\[\begin{aligned} \sum_{d|n}\mu(d)&={k\choose 0}-{k\choose 1}+{k\choose 2}+...+(-1)^k{k\choose k} \\ &=\sum_{i=0}^k(-1)^i{k\choose i} \\ &=(1-1)^k=0 \end{aligned} \]

最後一步由二項式定理:

\[(x+y)^z=\sum_{i=0}^n{z\choose i}x^iy^{z-i} \]

給出.