杜教篩小結


這個算法十分的強... 一般就是用於卡一道數論推結論題最后的\(20\)~\(30\)分... 被迫來學習QwQ

算法講解

這個一般用來篩一個積性函數在\(10^{10}\)左右的前綴和...

為了了解一下,可以看看 2016年國家候選隊論文中的任之洲積性函數求和的幾種方法

講講一些套路吧...

首先有ymy大佬告訴我的一個神奇東西,這個似乎很有用...

\(f*g=l\) (\(*\)\(Dirichlet\)卷積,下同) 若\(G\)\(L\)易求(\(g,l\)的前綴和) 則\(F\)易求 (\(f\)的前綴和).

\(\displaystyle L(n)-g(1)F(n)=\sum _{i=2}^n g(i) F(\lfloor\frac{n}{i}\rfloor)\). 證明的話可以參照后面的推導來證。

\(Dirichlet\)卷積 :

定義兩個數論函數\(f(x),g(x)\)\(Dirichlet\)卷積 (記作\((f*g)(x)\))

\[\displaystyle (f*g)(n)=\sum _{d|n} f(d)g(\frac{n}{d}) \]

引入例題

51nod 1244 莫比烏斯函數之和

題意

\(\displaystyle \sum _{i=a}^{b} \mu(i)\). (\(2\le a \le b \le 10 ^ {10}\))

題解

這道題一個裸的杜教篩...求個前綴和,再減一下就行了...

有一個有用的式子\(\displaystyle \sum _{d|n} \mu(d)=[n=1]\).(這個可以見我之前那篇博客)

解法一:

直接套用之前那個式子....

\(\mu * 1=\epsilon\) 此處\(\epsilon(x) =[x=1]\) 也就是上面那個

右邊前綴和都很好求\(\displaystyle \sum _{i=1}^{n} \epsilon(i)=1\).

然后你代入到之前那個式子就有 (令\(\displaystyle M(i)=\sum_{i=1}^{n} \mu(i)\))

\[\displaystyle 1-M(n)=\sum _{i=2}^{n} M(\lfloor \frac{n}{i} \rfloor) \]

解法二

我們來手推一下上面的式子qwq

然后就有個很顯然的式子(只有\(i=1\)時候有貢獻)

\[\therefore \displaystyle \sum_{i=1}^{n} \sum_{d|i}\mu(d)=1 \]

然后更換枚舉項,就是考慮每個\(d\)的對於它倍數的貢獻,然后交換和式就行了。

\[\therefore \displaystyle \sum_{i=1}^{n} \sum_{j=1}^{\lfloor \frac{n}{i}\rfloor}\mu(j)=1 \]

接下來我們就可以提出\(i=1\)時的一項,也就是\(\displaystyle \sum _{j=1}^{\lfloor \frac{n}{1}\rfloor=n} \mu(j)\)

\[\displaystyle \therefore \sum _{i=1}^{n} \mu(i)=1-\sum_{i=2}^{n} \sum_{j=1}^{\lfloor \frac{n}{i}\rfloor}\mu(j) \]

我們如果令\(\displaystyle M(n)=\sum_{i=1}^{n} \mu(i)\)就有和之前那個一樣的式子了

\[\displaystyle \therefore M(n)=1-\sum_{i=2}^{n} M(\lfloor \frac{n}{i}\rfloor) \]

然后我們對於這個式子就可以遞歸求解了,時間復雜度是\(\Theta(n^{\frac{2}{3}})\).

但是一定要記得要開個哈希表存儲一下,不然時間復雜度是個錯的!!!(來自ymy大佬的原話)

這個哈希表可以只開\(\sqrt n\)大小,因為\(\lfloor \frac{n}{i} \rfloor\)只有這么多種取值.

代碼我看了一下fjzzq大佬的博客 emmm... (同屆大佬太恐怖了)

我自己寫的一個... 注意一定要全程long long 不然有詭異的錯誤....

代碼

#include <bits/stdc++.h>
#define For(i, l, r) for(register ll i = (l), _end_ = (ll)(r); i <= _end_; ++i)
#define Fordown(i, r, l) for(register ll i = (r), _end_ = (ll)(l); i >= _end_; --i)
#define Set(a, v) memset(a, v, sizeof(a))
using namespace std;

typedef long long ll;

bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}

inline ll read() {
	ll x = 0, fh = 1; char ch = getchar();
	for (; !isdigit(ch); ch = getchar() ) if (ch == '-') fh = -1;
	for (; isdigit(ch); ch = getchar() ) x = (x<<1) + (x<<3) + (ch ^ '0');
	return x * fh;
}

void File() {
#ifdef zjp_shadow
	freopen ("1244.in", "r", stdin);
	freopen ("1244.out", "w", stdout);
#endif
}

const int N = 2e6 + 1e3;
ll mu[N], Limit, prime[N], cnt;
ll summu[N];
bitset<N> is_prime;

void Mu_Init(int maxn) {
	mu[1] = 1; int res; is_prime.set();
	is_prime[0] = is_prime[1] = false;
	For (i, 2, maxn) {
		if (is_prime[i]) { prime[++cnt] = i; mu[i] = -1; }
		For (j, 1, maxn) {
			res = prime[j] * i;
			if (res >= maxn) break ;
			is_prime[res] = false;
			if (i % prime[j]) mu[res] = -mu[i];
			else { mu[res] = 0; break ; }
		}
	}
	For (i, 1, maxn) summu[i] = summu[i - 1] + mu[i];
}

ll Size;
ll p1[N], p2[N], n;
inline ll &App(ll x) { if (x < Size) return p1[x]; return p2[n / x]; }

inline ll Mu_Sum_(ll x) {
	if (x <= Limit) return summu[x]; 
	ll &htr = App(x); if (htr != p2[0]) return htr;
	ll res = 1, Nextx;
	For (i, 2, x) {
		Nextx = x / (x / i);
		res -= 1ll * (Nextx - i + 1) * Mu_Sum_(x / i);
		i = Nextx;
	}
	return htr = res;
}

inline ll Mu_Sum(ll x) {
	Size = (int)(sqrt(x) + 0.5);
	Set(p1, -2333); Set(p2, -2333); n = x;
	return Mu_Sum_(x);
}

int main () {
	File();
	ll a, b;
	cin >> a >> b;
	Limit = N - (int)1e3; Mu_Init(Limit);

	cout << Mu_Sum(b) - Mu_Sum(a - 1) << endl;
	//cerr << "Time used: " << (double)clock() / CLOCKS_PER_SEC << "s" << endl;
	return 0;
}

BZOJ3944 : Sum

然后在簡單講一下求\(\varphi\)(歐拉函數)的前綴和吧...

題意 :

\(\displaystyle \sum_{i=1}^{n} \varphi(i)\)\(\displaystyle \sum _{i=1}^{n} \mu(i)\). (\(n \le 2^{31}-1\))

題解 :

其實和上一道題差不多啦...多求了一個\(\varphi\)嘛...

只要知道\(\varphi\)也有一個類似的結論$$\displaystyle \sum_{d|n} \varphi(d)=n$$

這個我不會證明 只有一個感性理解的方法...(來自具體數學)

你考慮所有分母為\(n\)的真分數和\(\frac{n}{n}\)(共有\(n\)個)

將分子和分母約去后,其他每個\(d|n\)\(d\)都對它具有\(\varphi(d)\)的貢獻咯...

例如\(n=6\).

\[\frac{1}{6},\frac{2}{6},\frac{3}{6},\frac{4}{6},\frac{5}{6},\frac{6}{6} \]

約分后就是

\[\frac{1}{6},\frac{1}{3},\frac{1}{2},\frac{2}{3},\frac{5}{6},\frac{1}{1} \]

這個就比較顯然了, 應該可以寫出證明的...(太懶也太菜了..)

然后像上一題一樣的啦~ 上道題兩個解法都能用用...

\(\varphi * 1=id\) \((id(x)=x)\) 我們令\(\displaystyle \phi(n) = \sum _ {i=1}^{n} \varphi(i)\).

就有一個顯然的式子

\[\displaystyle \frac{n(n+1)}{2}-\phi(n)=\sum_{i=2}^{n} \phi ({\lfloor \frac{n}{i} \rfloor}) \]

這個同上就行咯...

hihoCoder #1456 : Rikka with Lattice

這題也是一道好題!~

如果想看的,就在我另一篇博客上 無恥騙點擊...


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM