【51nod1355】斐波那契的最小公倍数(Min-Max容斥)(莫比乌斯反演)

传送门


题解:

首先所有相同的数只保留一个。

然后由于 g c d gcd gcd l c m lcm lcm可以表示成各个质因子的次数取 max ⁡ \max max min ⁡ \min min的情况,我们由 M i n − M a x Min-Max MinMax容斥可以得到:

l c m ( S ) = ∏ T ⊂ S g c d ( T ) − 1 ∣ T ∣ + 1 lcm(S)=\prod_{T\sub S}gcd(T)^{-1^{|T|+1}} lcm(S)=TSgcd(T)1T+1

注意上面的式子那里有双重指数。

斐波那契数有一个性质: g c d ( f n , f m ) = f g c d ( n , m ) gcd(f_n,f_m)=f_{gcd(n,m)} gcd(fn,fm)=fgcd(n,m)

这里给出一个证明,由于 f n = f n − 1 + f n − 2 f_n=f_{n-1}+f_{n-2} fn=fn1+fn2,归纳可知: g c d ( f n , f n − 1 ) = 1 gcd(f_n,f_{n-1})=1 gcd(fn,fn1)=1,同时有一个递推的性质: f n + m = f m + 1 ∗ f n + f m ∗ f n − 1 f_{n+m}=f_{m+1}*f_n+f_{m}*f_{n-1} fn+m=fm+1fn+fmfn1,由以上两个结论可以方便地推出上面那个性质。

g c d ( f n + m , f n ) = g c d ( f n − 1 ⋅ f m + f n ⋅ f m + 1 , f n ) = g c d ( f m , f n ) gcd(f_{n+m},f_n)=gcd(f_{n-1}\cdot f_m+f_n\cdot f_{m+1},f_n)=gcd(f_m,f_n) gcd(fn+m,fn)=gcd(fn1fm+fnfm+1,fn)=gcd(fm,fn)

下标上的迭代会在到达 g c d ( n , m ) gcd(n,m) gcd(n,m)时候停止。归纳可以知道 g c d ( f n , f m ) = f g c d ( n , m ) gcd(f_n,f_m)=f_{gcd(n,m)} gcd(fn,fm)=fgcd(n,m)

对我们要求的东西进行转化:

A n s = l c m ( f S ) = ∏ T ⊂ S g c d ( f T ) − 1 ∣ T ∣ + 1 = ∏ T ⊂ S f g c d ( T ) − 1 ∣ T ∣ + 1 \begin{aligned} Ans&=&&lcm(f_S)\\ &=&&\prod_{T\sub S}gcd(f_T)^{-1^{|T|+1}}\\ &=&&\prod_{T\sub S}f_{gcd(T)}^{-1^{|T|+1}} \end{aligned} Ans===lcm(fS)TSgcd(fT)1T+1TSfgcd(T)1T+1

感觉这个玩意不好算,观察到数据范围只有 1 e 6 1e6 1e6,所以我们感觉可以上 O ( A log ⁡ A ) O(A\log A) O(AlogA)的反演来一下。

考虑构造函数 g n g_n gn满足: f n = ∏ d ∣ n g d f_n=\prod_{d\mid n}g_d fn=dngd

于是可以继续化简: A n s = ∏ T ⊂ S ∏ d ∣ g c d ( T ) g d − 1 ∣ T ∣ + 1 = ∏ d g d ∑ T ⊂ S [ d ∣ g c d ( T ) ] ( − 1 ∣ T ∣ + 1 ) \begin{aligned} Ans&=&&\prod_{T\sub S}\prod_{d\mid gcd(T)}g_d^{-1^{|T|+1}}\\ &=&&\prod_{d}g_d^{\sum_{T\sub S}[d\mid gcd(T)](-1^{|T|+1})} \end{aligned} Ans==TSdgcd(T)gd1T+1dgdTS[dgcd(T)](1T+1)

我们观察一下上面这个式子中的指数: ∑ T ⊂ S [ d ∣ g c d ( T ) ] ( − 1 ∣ T ∣ + 1 ) \sum_{T\sub S}[d\mid gcd(T)](-1^{|T|+1}) TS[dgcd(T)](1T+1)

看上去不好处理,但是由这种集合的性质(或许应该称为 g c d gcd gcd的性质,但是总得来说还是来自容斥)我们知道:

∑ T ⊂ S [ d ∣ g c d ( T ) ] ( − 1 ∣ T ∣ + 1 ) = { 1 ∃ a ∈ S , [ d ∣ a ] 0 o t h e r w i s e \sum_{T\sub S}[d\mid gcd(T)](-1^{|T|+1})=\left\{ \begin{aligned} 1 &&& \exist a\in S ,[d\mid a]\\ 0 &&&otherwise \end{aligned} \right. TS[dgcd(T)](1T+1)={10aS,[da]otherwise

于是我们可以 O ( n log ⁡ n ) O(n\log n) O(nlogn)处理 g g g数组,然后随便做了。

但是实际上我们没必要算出 g g g数组,我们直接算出在所有 g g g的乘积中, f i f_i fi出现了多少次就行了。

这个也可以在调和级数时间内算出来。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

using std::cerr;
using std::cout;

cs int mod=1e9+7;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline void Inc(int &a,int b){(a+=b)>=mod&&(a-=mod);}
inline void Dec(int &a,int b){(a-=b)<0&&(a+=mod);}
inline int power(int a,int b,int res=1){
	for(;b;b>>=1,a=mul(a,a))(b&1)&&(res=mul(res,a));
	return res;
} 

cs int N=1e6+6;
int lim;
int f[N],cnt[N];

int n,ans=1;
bool a[N];

signed main(){
//	freopen("fiblcm.in","r",stdin);
	scanf("%d",&n);
	for(int re i=1;i<=n;++i){
		int x;scanf("%d",&x);
		a[x]=true;
		lim=std::max(lim,x);
	}
	f[1]=1;for(int re i=2;i<=lim;++i)f[i]=add(f[i-1],f[i-2]);
	for(int re i=lim;i>2;--i){
		for(int re j=i;j<=lim&&!a[i];j+=i)a[i]|=a[j];
		if(!a[i])continue;
		cnt[i]=1;
		for(int re j=i+i;j<=lim;j+=i)cnt[i]-=cnt[j];
		int tmp=cnt[i]%(mod-1);
		if(tmp<0)tmp+=mod-1;
		if(tmp)ans=mul(ans,power(f[i],tmp));
	}
	cout<<ans<<"\n";
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值