[BZOJ4833] [Lydsy1704月賽]最小公倍佩爾數(Min-Max 容斥)

題意

  • (1+2)n=e(n)+2f(n),g(n)=lcm(f(1),f(2),...,f(n))(1+\sqrt 2)^n=e(n)+\sqrt 2f(n),g(n)=\text{lcm}(f(1),f(2),...,f(n)),求 i=1ng(i)×i\sum\limits_{i = 1}^ng(i)\times i。(n106n\le10^6

挺巧妙的數學題,全程對着題解抄的,要推出來腦洞得足夠大。

首先可以知道: f(n)=2f(n1)+f(n2)f(n)=2f(n-1)+f(n-2)

引理一:對於 f(n)=af(n1)+bf(n2)f(n)=af(n-1)+bf(n-2) 形式的遞推式,如果有 gcd(a,b)=1\gcd(a,b)=1,那麼 gcd(f(a),f(b))=f(gcd(a,b))\gcd(f(a),f(b))=f(\gcd(a,b)),具體可以聯繫輾轉相除的過程用歸納法證明。

引理二:
lcm(S)=TS(1)T+1gcd(T)(Tϕ)\text{lcm}(S)=\prod_{T\subset S}(-1)^{|T|+1}\gcd(T)(T\neq\phi)
具體證明把 lcm\text {lcm} 看做指數取最大值,gcd\rm gcd 看做指數取最小值,套用 Min-Max 容斥即可。

定義U={1,2,...,n}U=\{1,2,...,n\}hh 滿足f(n)=dnh(d)f(n)=\prod\limits_{d|n}h(d),那麼 h(n)=f(n)dn,dnh(d)h(n)=\frac{f(n)}{\displaystyle\prod_{d|n,d\neq n}h(d)},我們可以 O(nlnn)O(n \ln n) 枚舉倍數計算。

由引理一和引理二可知:
g(n)=TU(1)T+1f(gcdiTi)g(n)=TU(1)T+1dgcdiTihdg(n)=\prod_{T\subset U}(-1)^{|T|+1}f(\gcd_{i\in T}i)\\ g(n)=\prod_{T\subset U}(-1)^{|T|+1}\prod_{d|\gcd\limits_{i\in T}i}h_d
Sd={d,2d,...,nd}S_d=\{d,2d,...,\lfloor\frac n d \rfloor\},那麼:
g(n)=d=1nhdTSd(1)T+1g(n)=\prod_{d = 1}^nh_d^{\sum\limits_{T\subset S_d}(-1)^{|T|+1}}

又因爲TSd(1)T+1=i=1Sd(1)i+1(Sdi)\sum\limits_{T\subset S_d}(-1)^{|T|+1}=\sum\limits_{i = 1}^{|S_d|}(-1)^{i+1}\binom {|S_d|} i,由二項式定理可知後面這個東西等於一,所以 g(n)=d=1nhdg(n)=\prod\limits_{d = 1}^nh_d

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;

int T, n, Mod, h[N], f[N];

inline int qpow(int a, int x)
{
	int ret = 1; 
	for (; x; x >>= 1, a = 1ll * a * a % Mod)
		if (x & 1) ret = 1ll * ret * a % Mod;
	return ret;
}

int main()
{
#ifdef ylsakioi
	freopen("4833.in", "r", stdin);
	freopen("4833.out", "w", stdout);
#endif
	f[0] = 0, f[1] = h[1] = 1;
	for (scanf("%d", &T); T -- ; )
	{
		scanf("%d%d", &n, &Mod);
		for (int i = 2; i <= n; ++ i)
			h[i] = f[i] = (2ll * f[i - 1] + f[i - 2]) % Mod;
		for (int i = 2; i <= n; ++ i)
		{
			int d = qpow(h[i], Mod - 2);
			for (int j = i << 1; j <= n; j += i) 
				h[j] = 1ll * h[j] * d % Mod;
		}
		int ans = 0, ret = 1; 
		for (int i = 1; i <= n; ++ i) 
		{
			ret = 1ll * ret * h[i] % Mod;
			(ans += 1ll * ret * i % Mod) %= Mod;
		}
		printf("%d\n", ans);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章