【51nod1355】斐波那契的最小公倍数(min-max容斥)

【51nod1355】斐波那契的最小公倍数(min-max容斥)

题面

51nod

题解

显然直接算还是没法算的,所以继续考虑\(min-max\)容斥计算。

\[lcm(S)=\prod_{T\subset S}gcd(T)^{(-1)^{|T|+1}} \]

而斐波那契数列满足\(gcd(f(a),f(b))=f(gcd(a,b))\)
于是和最小公倍佩尔数一样的类似处理

\[lcm(S)=\prod_{i=1}^{\infty}f(i)^{\sum_{T\subset S}[gcd(T)=i](-1)^{|T|+1}} \]

\(a[i]\)是上面那一堆东西,\(b[i]=\sum_{i|d}a[i]\)
然后发现

\[b[i]=\prod_{T\subset S}[i|gcd(T)](-1)^{|T|+1} \]

只和是否存在\(i\)的倍数相关,存在就是\(1\),不存在就是\(0\)
那么预处理一下就可以算出\(b\)
而根据莫比乌斯反演,有

\[a[i]=\sum_{i|d}\mu(\frac{d}{i})b[d] \]

所以答案式就是:

\[\begin{aligned} lcm(S)&=\prod_{i=1}^{\infty}f(i)^{\sum_{T\subset S}[gcd(T)=i](-1)^{|T|+1}}\\ &=\prod_{i=1}^{\infty}f(i)^{\sum_{i|d}\mu(\frac{d}{i})b[d]} \end{aligned}\]

也可以预处理之后爆算了。

#include<iostream>
#include<cstdio>
using namespace std;
#define MOD 1000000007
#define MAX 1001000
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int cnt[MAX];
bool zs[MAX];
int pri[MAX],tot,mu[MAX];
int fpow(int a,int b){int s=1;while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}return s;}
int n,ans=1,a[MAX],b[MAX],f[MAX];
void Sieve(int n)
{
	mu[1]=1;
	for(int i=2;i<=n;++i)
	{
		if(!zs[i])pri[++tot]=i,mu[i]=-1;
		for(int j=1;j<=tot&&i*pri[j]<=n;++j)
		{
			zs[i*pri[j]]=true;
			if(i%pri[j])mu[i*pri[j]]=-mu[i];
			else break;
		}
	}
}
int main()
{
	n=read();
	for(int i=1;i<=n;++i)b[read()]=1;
	for(int i=1;i<MAX;++i)
		for(int j=i+i;j<MAX;j+=i)
			b[i]|=b[j];
	f[1]=f[2]=1;for(int i=2;i<MAX;++i)f[i]=(f[i-1]+f[i-2])%MOD;
	Sieve(MAX-1);
	for(int i=1;i<MAX;++i)
		for(int j=i;j<MAX;j+=i)
			a[i]+=mu[j/i]*b[j];
	for(int i=1;i<MAX;++i)
		if(a[i]>0)ans=1ll*ans*fpow(f[i],a[i])%MOD;
		else if(a[i]<0)ans=1ll*ans*fpow(f[i],MOD-1+a[i])%MOD;
	printf("%d\n",ans);
	return 0;
}
posted @ 2019-05-25 20:28  小蒟蒻yyb  阅读(564)  评论(0编辑  收藏  举报