51nod 1355 斐波那契的最小公倍数

Description

斐波那契数列定义如下:

\[f[n]= \begin{cases} 1 , & \text {if $n$ is equal to $0$ or $1$} \\ f(n-1) + f(n-2), & \text{otherwise} \end{cases} \]

给出 \(n\) 个正整数 \(a_1, a_2,\cdots ,a_n\) ,求对应的斐波那契数的最小公倍数,由于数字很大,输出 \(\bmod{ 1000000007}\) 的结果即可。

\(2\le N \le 50000,1 \le a_i\le 1000000\)

Solution

首先对于集合 \({S}\)

\[lcm(S)=\prod_{T\subseteq S,T\ne\emptyset} \gcd(T) ^{(-1)^{|T|+1}} \]

对于斐波那契数列有

\[f(\gcd(a,b)) = \gcd(f(a), f(b)) \]

于是有

\[\begin{align} lcm(f_S) &=\prod_{T\subseteq S,T\ne\emptyset} \gcd(f_T)^{(-1)^{|T|+1}} \\ &=\prod_{T\subseteq S,T\ne\emptyset} f_{\gcd(T)}^{(-1)^{|T|+1}} \end{align} \]

定义数列 \(g\)

\[f_n=\sum_{d|n}g_d \]

于是有

\[\begin{align} lcm(f_S) &=\prod_{T\subseteq S,T\ne\emptyset} \gcd(f_T)^{(-1)^{|T|+1}} \\ &=\prod_{T\subseteq S,T\ne\emptyset} f_{\gcd(T)}^{(-1)^{|T|+1}} \\ &=\prod_{T\subseteq S,T\ne\emptyset} (\prod_{d|\gcd(T)}g_d)^{(-1)^{|T|+1}} \\ &=\prod_d g_d^{\sum_{T\subseteq S,T\ne \emptyset,d|\gcd(T)} (-1)^{|T|+1}} \end{align} \]

另有

\[\sum_{T\subseteq S,T\ne \emptyset,d|\gcd(T)} (-1)^{|T|+1} = \begin{cases} 1, & \exists x \in S,d|x\\ 0, & \text{otherwise} \end{cases} \]

于是

\[\begin{align} lcm(f_S) &=\prod_{T\subseteq S,T\ne\emptyset} \gcd(f_T)^{(-1)^{|T|+1}} \\ &=\prod_{T\subseteq S,T\ne\emptyset} f_{\gcd(T)}^{(-1)^{|T|+1}} \\ &=\prod_{T\subseteq S,T\ne\emptyset} (\prod_{d|\gcd(T)}g_d)^{(-1)^{|T|+1}} \\ &=\prod_d g_d^{\sum_{T\subseteq S,T\ne \emptyset,d|\gcd(T)} (-1)^{|T|+1}} \\ &=\prod_{\exists x \in S,d|x} g_d \end{align} \]

然后就可以直接算了。

另外对于 \(g\)

\[g_n=f_n\times(\prod _{d|n,d\ne n} g_d)^{-1} \]

#include<bits/stdc++.h>
using namespace std;

template <class T> void read(T &x) {
	x = 0; bool flag = 0; char ch = getchar(); for (; ch < '0' || ch > '9'; ch = getchar()) flag |= ch == '-';
	for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - 48; flag ? x = 0 - x : 0;
}

#define N 10000010
#define rep(i, a, b) for (auto i = (a); i <= (b); ++i)
#define drp(i, a, b) for (auto i = (a); i >= (b); --i)
#define ll long long
#define P 1000000007

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

int qpow(int x, int k) {
	int ret = 1;
	for (; k; k >>= 1, x = 1ll * x * x % P) if (k & 1) ret = 1ll * ret * x % P;
	return ret;
}

void init() {
	f[1] = 1;
	rep(i, 2, n) f[i] = (f[i - 2] + f[i - 1]) % P;
	rep(i, 1, n) g[i] = f[i];
	rep(i, 1, n) {
		int inv = qpow(g[i], P - 2);
		for (int j = i + i; j <= n; j += i) g[j] = 1ll * g[j] * inv % P;
	}
}

bool vis[N];

int main() {
	read(n); int _n = 0;
	rep(i, 1, n) read(a[i]), _n = max(a[i], _n), vis[a[i]] = 1;
	n = _n;
	init();
	int ans = 1;
	rep(i, 1, n) {
		bool tag = 0;
		for (int j = i; j <= n; j += i) if (vis[j]) { tag = 1; break; }
		if (tag) ans = 1ll * ans * g[i] % P;
	}
	printf("%d", ans);
	return 0;
}
posted @ 2018-10-12 20:20  aziint  阅读(272)  评论(0编辑  收藏  举报
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.