1. 程式人生 > >【題解】[國家集訓隊]Crash的數字表格 / JZPTAB

【題解】[國家集訓隊]Crash的數字表格 / JZPTAB

改變 sqrt 完成 base getchar () efi long tab

  求解\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}lcm\left ( i,j \right )\)。

有\(lcm\left ( i,j \right )=\frac{ij}{gcd\left ( i,j \right )}\),

所以原本的式子轉化為:\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}\frac{ij}{gcd\left ( i,j \right )}\)。

註意到\(i, j\) 均為 \(gcd\left ( i,j \right )\) 的倍數,且原式中有除法不好處理,

所以我們改為枚舉\(gcd\left ( i,j \right )\) 的倍數。

有:\(\sum_{d = 1}^{n} d \sum_{i = 1}^{\frac{n}{d}}\sum_{j = 1}^{\frac{m}{d}}ij\left [ gcd\left ( i,j \right ) = 1 \right]\)。

後面的式子套路的來一發反演:

\(\sum_{d = 1}^{n} d \sum_{i = 1}^{\frac{n}{d}}\sum_{j = 1}^{\frac{m}{d}}ij\sum_{k|gcd\left ( i,j \right )}\mu \left ( k \right )\)

註意這裏面有一個乘積的項,可以理解為是任意數字的兩兩匹配,即:

\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}ij = \left ( 1 + 2 + ... + n \right )\left ( 1 + 2 + ... + m \right )\)

所以轉化為:

\(\sum_{d = 1}^{n} d \sum_{k = 1}^{\frac{n}{d}}\mu \left ( k \right )sum\left ( \left \lfloor \frac{n}{dk} \right \rfloor \right )sum\left ( \left \lfloor \frac{m}{dk} \right \rfloor \right )\)

依然是套路的改變枚舉項為 \(dk\)

\(\sum_{T = 1}^{n} sum\left ( \left \lfloor \frac{n}{T} \right \rfloor \right )sum\left ( \left \lfloor \frac{m}{T} \right \rfloor \right )\sum_{d|T}d*\mu \left ( \frac{T}{d} \right )\)

  到這裏我們已經實現了第一步:前面的部分可以數論分塊\(O\left ( \sqrt{n} \right )\)處理,只要我們能夠通過線性篩處理出後面的一部分,這道題目就完成了。為了實現線性篩,我們對於後面部分進行觀察。我們令\(F[t] = \sum_{d|T}d*\mu \left ( \frac{T}{d} \right )\) 。

  首先,\(F[i]\)當 \(i\) 為質數時,\(F[i]\) 的值很容易確定為 \(i * (1 - i)\)。 註意到它實際上是 \(id * \mu\) ,是積性函數。所以在線性篩中若 \(i = x * y\) ,(其中 \(x\) 為 \(i\) 的最小質因子),當 \(y \ mod \ x \neq 0\) 時說明二者互質,則 \(F[i] = F[x] * F[y]\)。

  然後考慮當\(y \ mod \ x = 0\)的情況,這說明這兩個部分中均含有最小的質因子。註意因為卷入了一個 \(\mu\),所以有平方因子時的值都不會造成貢獻。也就是說取值範圍和 \(y\) 仍然是相同的,只不過是系數改變了。所以此時 \(F[i] = F[y] * x \)。然後此題就圓滿解決啦~~~

#include <bits/stdc++.h>
using namespace std;
#define maxn 10005000
#define int long long
#define mod 20101009
int n, m, N, maxx = maxn - 1e3;
int tot, pri[maxn], inv2;
int ans, f[maxn];
bitset <maxn> is_prime;

int read()
{
    int x = 0, k = 1;
    char c;
    c = getchar();
    while(c < 0 || c > 9) { if(c == -) k = -1; c = getchar(); }
    while(c >= 0 && c <= 9) x = x * 10 + c - 0, c = getchar();
    return x * k;
}

int qpow(int x, int times) 
{
    int base = 1;
    for(; times; times >>= 1, x = (x * x) % mod)
        if(times & 1) base = (base * x) % mod;
    return base;
}
int Sum(int x) { x %= mod; return ((x * (x + 1)) % mod * inv2 % mod);}

void Get_F()
{
    f[1] = 1;
    for(int i = 2; i <= maxx; i ++)
    {
        if(!is_prime[i]) pri[++ tot] = i, f[i] = i * (1ll - i) % mod;
        for(int j = 1; j <= tot; j ++)
        {
            int K = i * pri[j]; if(K > maxx) break;
            is_prime[K] = 1;
            if(!(i % pri[j])) { f[K] = f[i] * pri[j] % mod; break; }
            else f[K] = f[i] * f[pri[j]] % mod;
        }
    }
    for(int i = 1; i <= maxx; i ++) f[i] = (f[i] + f[i - 1]) % mod;
}

signed main()
{
    n = read(), m = read(), N = min(n, m);
    maxx = min(n, m); inv2 = qpow(2, mod - 2);
    Get_F();
    for(int l = 1, r; l <= N; l = r + 1)
    {
        r = min((n / (n / l)), (m / (m / l)));
        int ret = Sum(n / l) * Sum(m / l) % mod;
        ans = (ans + (ret * (f[r] - f[l - 1]) % mod)) % mod; 
    }
    printf("%lld\n", (ans + mod) % mod);
    return 0;
} 

【題解】[國家集訓隊]Crash的數字表格 / JZPTAB