[51nod1355] 斐波那契的最小公倍数

Description

给定 (n) 个正整数 (a_1,a_2,...,a_n),求 ( ext{lcm}(f_{a_1},f_{a_2},...,f_{a_n}))。其中 (f_i) 是斐波那契数列第 (i) 项。 (nleq 50000,a_ileq 10^6)

Sol

首先关于集合 (S)( ext{lcm})可以用类似( ext{min-max})容斥的式子搞一下,变成跟(gcd)有关:

[ ext{lcm}(T)=prod_{Ssubseteq T} gcd(S)^{left((-1)^{|S|+1} ight)} ]

所以原式就可以变成:

[ ext{lcm}(f_{{T}})=prod_{Ssubseteq T} (f_{gcd{S}})^{left((-1)^{|S|+1} ight)} ]

看见这个(gcd)想到莫比乌斯反演

设:

[f_n=prod_{dmid n} g_d ]

那么:

[g_n=frac{f_n}{prodlimits_{dmid nland d e n} g_d} ]

所以原式化为:

[egin{aligned} ext{lcm}(f_{{T}})&=prod_{Ssubseteq T}left(prod_{dmid gcd(S)} g_d ight) ^{left((-1)^{|S|+1} ight)}\ &= prod_{d} g_d^{;;sumlimits_{Ssubseteq Tland dmid gcd(S)} (-1)^{|T|+1}} end{aligned} ]

然后看看这个式子等于什么:

[sumlimits_{Ssubseteq Tland dmid gcd(S)} (-1)^{|T|+1} ]

把所有在 (T) 中且是 (d) 的倍数的 (x) 扔进一个新集合 (S') 中,设(|S'|=n),那么:

[egin{aligned} &sumlimits_{Ssubseteq Tland dmid gcd(S)} (-1)^{|T|+1}\ =&sum_{i=1}^n {nchoose i} (-1)^{i+1}\ =&(-1)left(sum_{i=1}^n {nchoose i}(-1)^i ight)\ =&(-1)left( (1-1)^n-1 ight)\ =&epsilon(n eq 0) end{aligned} ]

也就是说,只要有一个元素是 (d) 的倍数,那么 (g_d) 就有贡献。

Code

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
const int N=1e6+5;
const int mod=1e9+7;

int n,mx,a[N],f[N],g[N];

int ksm(int a,int b=mod-2,int ans=1){
	while(b){
		if(b&1) ans=1ll*ans*a%mod;
		a=1ll*a*a%mod;b>>=1;
	} return ans;
}

void init(int n){
	f[1]=1;
	for(int i=2;i<=n;i++)
		f[i]=(f[i-1]+f[i-2])%mod;
	for(int i=1;i<=n;i++)
		for(int j=i+i,p=ksm(f[i]);j<=n;j+=i)
			f[j]=1ll*f[j]*p%mod;
}

signed main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]),mx=max(mx,a[i]),g[a[i]]=1;
	init(mx); int ans=1;
	for(int i=1;i<=mx;i++)
		for(int j=i;j<=mx;j+=i)
			if(g[j]){
				ans=1ll*ans*f[i]%mod;
				break;
			}
	printf("%d
",ans); return 0;
}

原文地址:https://www.cnblogs.com/YoungNeal/p/10397511.html