51nod 1355 斐波那契的最小公倍数 莫比乌斯反演+数学
来源:互联网 发布:陈乔恩长相知乎 编辑:程序博客网 时间:2024/06/11 10:20
题意
F(0) = 0 F(1) = 1
F(n) = F(n-1) + F(n-2)
给出n个正整数a1, a2,…… an,求对应的斐波那契数的最小公倍数,由于数字很大,输出Mod 1000000007的结果即可。
2 <= N <= 50000,1 <= ai <= 1000000。
分析
跪zyz大爷写的题解。
首先有个结论就是
证明的话可以根据
还有一个结论就是
证明的话可以考虑知道每个子集的最小值通过容斥来求全集的最大值。
为什么这样是对的呢?如果真的无法把这个东西看做容斥的话可以这样想:
我们把全集从大到小排序后,第n个数出现的次数就是
注意到这条式子只有当n=0时为1否则为0,因此得出来的是最大值。
从而可以得到
然后我们构造数列
那么有
注意到其指数上的式子
当存在
那么有
在求出
求
那么
代码
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const int N=1000005;const int MOD=1000000007;int n,f[N];bool vis[N];int read(){ int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f;}int ksm(int x,int y){ int ans=1; while (y) { if (y&1) ans=(LL)ans*x%MOD; x=(LL)x*x%MOD;y>>=1; } return ans;}int main(){ n=read();int mx=0; for (int i=1;i<=n;i++) { int x=read(); mx=max(mx,x);vis[x]=1; } for (int i=1;i<=mx;i++) for (int j=i;j<=mx;j+=i) vis[i]|=vis[j]; f[1]=f[2]=1; for (int i=3;i<=mx;i++) f[i]=f[i-1]+f[i-2],f[i]-=f[i]>=MOD?MOD:0; int ans=1; for (int i=1;i<=mx;i++) { int ny=ksm(f[i],MOD-2); for (int j=i*2;j<=mx;j+=i) f[j]=(LL)f[j]*ny%MOD; if (vis[i]) ans=(LL)ans*f[i]%MOD; } printf("%d",ans); return 0;}
阅读全文