51nod 1355 斐波那契的最小公倍数

原题链接.

###题解:
这题肯定是我做过的最简单的八级算法题了。

F i Fi Fi为斐波拉契序列的第i项。

通过打表可得:
g c d ( F n , F m ) = F g c d ( n , m ) gcd(Fn,Fm)=F_{gcd(n,m)} gcd(Fn,Fm)=Fgcd(n,m)

接下来尝试去证明这个结论。

首先斐波拉契序列有一个递推式:
F n + m = F n − 1 ∗ F m + F n ∗ F m + 1 F_{n+m}=F_{n-1}*F_{m}+F_{n}*F_{m+1} Fn+m=Fn1Fm+FnFm+1

还有一个结论就是 g c d ( F n − 1 , F n ) = 1 gcd(F_{n-1},F_n)=1 gcd(Fn1,Fn)=1

这两个结论都是显然的,就不证明了。

不妨设 n &lt; m n&lt;m n<m,那么
g c d ( F n , F m ) gcd(Fn,Fm) gcd(Fn,Fm)
= g c d ( F n , F n − 1 ∗ F m − n + F n ∗ F m − n + 1 ) =gcd(F_n,F_{n-1}*F_{m-n}+F_n*F_{m-n+1}) =gcd(Fn,Fn1Fmn+FnFmn+1)
因为 F n ∗ F m − n + 1 F_n*F_{m-n+1} FnFmn+1一定是 F n F_n Fn的倍数,因此可以直接去掉。
= g c d ( F n , F n − 1 ∗ F m − n ) =gcd(F_n,F_{n-1}*F_{m-n}) =gcd(Fn,Fn1Fmn)
因为 g c d ( F n , F n − 1 ) = 1 gcd(F_n,F_{n-1})=1 gcd(Fn,Fn1)=1,所以可以去掉
= g c d ( F n , F m − n ) =gcd(F_n,F_{m-n}) =gcd(Fn,Fmn)

发现下标在更相减损,归纳可得 g c d ( F n , F m ) = F g c d ( n , m ) gcd(Fn,Fm)=F_{gcd(n,m)} gcd(Fn,Fm)=Fgcd(n,m)

l c m lcm lcm有一个容斥求法:

l c m ( a 1 , a 2 , … , a n ) lcm(a1,a2,…,an) lcm(a1,a2,,an)
= ∏ b ∈ a 且 b ≠ ∅   g c d ( b 1 , b 2 , … , b ∣ b ∣ ) − 1 ∣ b ∣ + 1 =\prod_{b∈a且b≠∅}~gcd(b1,b2,…,b_{|b|})^{-1^{|b|+1}} =bab̸= gcd(b1,b2,,bb)1b+1

证明可通过对每一个质因子单独讨论得到。

q i q_i qi a i a_i ai含质因子p的幂次。

原式等价于:
= ∏ b ∈ q 且 b ≠ ∅   m i n ( b i ) − 1 ∣ b ∣ + 1 =\prod_{b∈q且b≠∅}~min(b_i)^{-1^{|b|+1}} =bqb̸= min(bi)1b+1
假设已经把q从小到大排序了
= ∑ k = 1 n q k ∗ ∑ i = 0 n − k C n − k i ∗ ( − 1 ) i =\sum_{k=1}^n q_k *\sum_{i=0}^{n-k}C_{n-k}^i*(-1)^{i} =k=1nqki=0nkCnki(1)i
= ∑ k = 1 n q k ∗ [ n − k = 0 ] =\sum_{k=1}^n q_k*[n-k=0] =k=1nqk[nk=0]
= q n =q_n =qn
= 排 序 前 的 m a x ( q ) =排序前的max(q) =max(q)

把每个质因子合并起来即得证。

f i f_i fi表示 g c d gcd gcd恰好为 i i i的每种方案×这种方案的容斥系数(就是那个-1的多少次方)的和。

直接算不好算,于是反演一下, g i g_i gi定义类似,为 g c d gcd gcd i i i的倍数的XXX

设读入的n个数中有k个数是i的倍数,则 g ( k ) = [ k &gt; 0 ] g(k)=[k&gt;0] g(k)=[k>0]

g i = ∑ i ∣ j f j g_i=\sum_{i|j}f_j gi=ijfj
f i = ∑ i ∣ j g j ∗ μ ( j / i ) f_i=\sum_{i|j}g_j*\mu(j/i) fi=ijgjμ(j/i)

至此此题完成,写起来真的好写,就是证明有点多。

Code:

#include<cstdio> 
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;

const int mo = 1e9 + 7;

const int N = 1e6;

int n, x;
bool bz[N + 1];
int p[N], mu[N + 1], s[N + 1], f[N + 1];

ll ksm(ll x, ll y) {
	if(y < 0) x = ksm(x, mo - 2), y = -y;
	ll s = 1;
	for(; y; y /= 2, x = x * x % mo)
		if(y & 1) s = s * x % mo;
	return s;
}

int main() {
	f[0] = 0; f[1] = 1; mu[1] = 1;
	fo(i, 2, N) {
		f[i] = (f[i - 1] + f[i - 2]) % mo;
		if(!bz[i]) p[++ p[0]] = i, mu[i] = -1;
		for(int j = 1; i * p[j] <= N; j ++) {
			int k = i * p[j]; bz[k] = 1;
			if(i % p[j] == 0) {mu[k] = 0; break;}
			mu[k] = -mu[i];
		}
	}
	scanf("%d", &n);
	fo(i, 1, n) scanf("%d", &x), s[x] ++;
	fo(i, 1, N) {
		fo(j, 2, N / i) s[i] += s[i * j];
		s[i] = s[i] > 0;
	}
	fo(i, 1, N) fo(j, 2, N / i) s[i] += s[i * j] * mu[j];
	ll ans = 1; fo(i, 1, N) ans = ans * ksm(f[i], s[i]) % mo;
	printf("%lld", ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值