覆盤 \(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 ...