51nod1220 約數之和

2022-09-09 17:54:12 字數 3843 閱讀 1285

覆盤 \(bindir0\) 講的數論清真題,寫一篇題解來禍害自己。

給定 \(n\) ,求

\[\sum_ ^ \sum_ ^ \sigma(i \cdot j)

\]結果對 \(10 ^ 9 + 7\) 取模。

\(2\leq n \leq 10 ^ 9\)

無腦轉化式子+打表+無腦亂卷函式=不用推式子!

按照一貫的套路,把 \(\sigma\) 換一種寫法,但是注意 \(\sigma\) 注意有可能會算重,所以要限制列舉,要求兩個因數相對獨立:

\[\sum_ ^ \sum_ ^ \sum_ \sum_ p \cdot q [i / p \perp q]

\]寫法不太好看,改成:

\[\sum_ ^ \sum_ ^ \sum_ \sum_ i / p \cdot q [p \perp q]

\]然後是另外乙個常見的套路,就是交換列舉順序,注意下面的 \(i \cdot p\) 就是對應上面的 \(i\) ,要清楚列舉東西的含義:

\[\sum_ ^ \sum_ ^ q / p \cdot [p \perp q] \sum_ ^ i \cdot p \sum_ ^ 1

\]稍稍化簡一下,把 \(p\) 消掉,然後後面兩坨可以直接寫成公式的樣子,稍微換一下位置:

\[\sum_ ^ \frac \sum_ ^ \lfloor n / q \rfloor \cdot q \cdot [p \perp q]

\]感覺最後面那個限制讓我們很難放開手腳去把 \(p\) 和 \(q\) 分開算,據說是有兩種做法,但因為本人能力有限,就先說一下莫反的做法。

以限制條件作為基礎,可以很自然地寫出兩個函式形如:

\[f(k) = \sum_ ^ \frac \sum_ ^ \lfloor n / q \rfloor \cdot q \cdot [\gcd(p, q) = k]\\

g(k) = \sum_ ^ \frac \sum_ ^ \lfloor n / q \rfloor \cdot q \cdot [k | \gcd(p, q)]

\]然後很好寫莫反的式子:

\[g(k) = \sum_ f(d)\\

f(k) = \sum_ \mu(\frac) \cdot g(d)

\]因為我們最終要求的答案就是 \(f(1)\) ,所以就把函式帶進去,同時如我們要讓最後的式子能通過什麼遞推算,還是把後面的那兩坨和 \(d\) 沒有關係的式子硬提出來乙個 \(d\) ,然後注意保持列舉的東西的一致性:

\[ans = f(1) = \sum_ \mu(d) \cdot g(d)\\

\longrightarrow ans = f(1) = \sum_ \mu(d) \cdot \sum_ ^ \frac \sum_ ^ \lfloor n / qd \rfloor \cdot qd

\]最後面的 \(d\) 可以甩到前面去,但就不單獨列出來了。然後來看 \(p\) 這一層的式子大概是個什麼鬼。

\[\sum_ ^ \frac\\

\longrightarrow \sum_ ^ \sum_^ i\\

\]其實這樣已經化不下去了,那就繼續用老套路,調換列舉順序,算 \(i\) 出現的次數:

\[\longrightarrow \sum_ ^ \sum_ i\\

\]這樣還是不行,因為 \(p\) 沒有單獨分出來,但是發現下取整對應大於,放縮一下可以得到:

\[\longrightarrow \sum_ ^ \sum_ i\\

\longrightarrow \sum_ ^ \lfloor n / i \rfloor \cdot i\\

\]然後你發現這和後面那坨不謀而合,所以快樂合併:

\[ans = f(1) = \sum_ \mu(d) \cdot d \cdot (\sum_ ^ \lfloor n / i d \rfloor \cdot i) ^ 2

\]又不快樂了,因為後面那坨壓根和常用函式沒關係,雖然沒有約束條件,可以放開手腳了,但是卷積卷不起來呀。。

於是又回頭來看剛剛推得的式子,可以考慮考慮他的含義,等於是說這個範圍內包含因子 \(i\) 的數一共有 \(\lfloor n / i \rfloor\) 個,不重,因為每個因子都列舉到了,不漏,那合到一起不就剛好是 \(\sum\sigma\) 嗎:

\[\sum_ ^ \lfloor n / i \rfloor \cdot i\\

\longrightarrow \sum_ ^ \sigma (i)\\

\therefore ans = f(1) = \sum_ \mu(d) \cdot d \cdot \big(\sum_ ^ \sigma(i) \big) ^ 2

\]終於該篩法上場了,但是因為本人水平有限,只會杜教篩的做法,min25篩可能要等到千年以後了。。

所以這樣來看現在我們就要卷兩個東西,乙個是 \(\mu \cdot id\) ,另乙個是 \(\sigma\) 。

前者的話我們直接選乙個 \(id\) 卷上去,正好能把原式裡面的 \(id\) 卷掉:

\[((\mu \cdot id) * id)(n) = \sum_ \mu(d) \cdot d \cdot \frac\\

\longrightarrow \sum_ \mu(d) \cdot n \rightarrow [n = 1]

\]嗯,好極了!

後者的話乍一看並不知道有什麼常用公式能套上去,但是,我們知道根據定義,有這樣幾個東西:

\[\mu * i = [n = 1] \\

\sigma = id * i\\

\]目標乍現!!

所以 \(\sigma * \mu = id\) !!

該卷啥都已經清楚了,直接套杜教篩的板子就可以了。

注意線性篩預處理 \(\sigma\) 的時候要在多存乙個陣列記錄乙個數是被哪個質數篩中的,這樣才能消去不互質的兩個數重複的因子,從而才能合併。

/*

*/#include#define ri register int

using namespace std;

typedef long long ll;

const int n = 1e6 + 10, m = 1e6;

const ll mod = 1e9 + 7, inv2 = 500000004, inv6 = 166666668;

ll mud[n], mu[n], sig[n], zs[n];

int n, pri[n], tot; bool vis[n];

unordered_mapans_mud, ans_mu, ans_sig;

inline ll read()

while (ch >= '0' && ch <= '9')

return s * w;

}inline void init()

mu[i * pri[j]] = -mu[i];

zs[i * pri[j]] = pri[j] + 1;

sig[i * pri[j]] = sig[i] * zs[i * pri[j]];

} }for (ll i = 1; i <= m; ++i)

}inline ll s(ll x, ll y)

inline ll g(ll x)

inline ll get_mu(ll x)

return ans_mu[x] = ans;

}inline ll get_mud(ll x)

return ans_mud[x] = ans;

}inline ll get_sig(ll x)

return ans_sig[x] = ans;

}inline ll get_ans(ll x)

return ans;

}int main()

51nod1220 約數之和

首先列出題目要求的式子 an s i 1n j 1n d ij an s i 1n j 1n a i b j ajb a,b 1 你問我為啥?我也不知道 an s i 1n j 1n a i b j ajb d a b d d 1 n d d an d bn a in b j najb d 1n d...

51Nod 1220 約數之和 PE439

i 表示i的約數和 n i 1 nj 1 ij ni 1 nj 1 w i v jwv d w d i v u d 我們嘗試把d提前 會發現有 nd 1 d u d n d i 1 i 2後面 n d i 1 i 2可以看作f n d 對於 n d i 1 i 我們可以小資料預處理 大資料o n0....

51nod 1040 最大公約數之和

1040 最大公約數之和 rihkddd 基準時間限制 1 秒 空間限制 131072 kb 分值 80 難度 5級演算法題 給出乙個n,求1 n這n個數,同n的最大公約數的和。比如 n 6 1,2,3,4,5,6 同6的最大公約數分別為1,2,3,2,1,6,加在一起 15 input 1個數n ...