Problem
斐波那契的最小公倍数
TimeLimit:3Sec
MemoryLimit:131072KB
Description
斐波那契数列定义如下:
F(0)=0F(1)=1F(n)=F(n−1)+F(n−2)
给出n个正整数a1,a2,⋯an,求对应的斐波那契数的最小公倍数,由于数字很大,输出模 1000000007的结果即可。
例如:{1,3,6,9}, 对应的斐波那契数为:{1,2,8,34}, 他们的最小公倍数为136。
第1行1个数N,表示数字的数量。(2≤N≤50000)。
第2至N+1行每行1个数,对应ai。(1≤ai≤1000000)。
Output
输出lcm(F(a1),F(a2),⋯,F(an))mod1000000007的结果。
Output示例
标签:Min-Max容斥
Solution
烂大街的套路题,我居然没见过QAQ。
以下内容均转载自某乎(张一钊)。
因为是斐波那契数列,有gcd(fp,fq)=fgcd(p,q)。
由Min−Max容斥可得lcm{S}=∏T⊆S,T=∅gcd{T}(−1)∣T∣+1。
于是lcm{fS}=∏T⊆S,T=∅fgcd{T}(−1)∣T∣+1。
构造{g},使得fn=∏d∣ngd,则lcm{fS}=∏T⊆S,T=∅∏d∣gcd{T}gd(−1)∣T∣+1。
即有lcm{fS}=∏dgd∑T⊆S,T=∅,d∣T(−1)∣T∣+1。
考虑gd的指数的意义,可知
T⊆S,T=∅,d∣T∑(−1)∣T∣+1={10∣{a∣a∈S,d∣a}∣>0otherwise
因而lcm{fS}=∏∃a∈S,d∣agd,若知道可在O(RlogR)时间内计算(R为值域即max{S})。
将g定义式中的gn单独拿出来,有gn=fn⋅(∏d∣n,d=ngd)−1,时间复杂度由于是调和级数也为O(RlogR)。
总复杂度O(RlogR)。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #include <bits/stdc++.h> #define MX 1000000 #define P 1000000007 using namespace std; typedef long long lnt; template <class T> inline void read(T &x) { x = 0; int c = getchar(), f = 1; for (; !isdigit(c); c = getchar()) if (c == 45) f = -1; for (; isdigit(c); c = getchar()) (x *= 10) += f*(c-'0'); } int n; bool mrk[MX+5]; lnt f[MX+5], g[MX+5]; lnt inv(lnt x) { lnt k = P-2, ret = 1; for (; k; k >>= 1, x = x*x%P) if (k&1) ret = ret*x%P; return ret; } void init() { f[1] = f[2] = g[1] = g[2] = 1; for (int i = 3; i <= MX; i++) f[i] = g[i] = (f[i-2]+f[i-1])%P; for (int i = 1; i <= MX; i++) { lnt invg = inv(g[i]); for (int j = i+i; j <= MX; j += i) g[j] = g[j]*invg%P; } } int main() { read(n), init(); lnt ans = 1; for (int i = 1, x; i <= n; i++) read(x), mrk[x] = true; for (int i = 1; i <= MX; i++) { bool flag = false; for (int j = i; j <= MX; j += i) if (mrk[j]) {flag = true; break;} if (flag) ans = ans*g[i]%P; } return printf("%lld\n", ans), 0; }
|