woc好神
不愧是8级题
题意:
给定 (n(nle 50000)) 个正整数 (a_i(1le a_ile 10^6))
你需要计算:
[ ext{lcm}(F(a_1),F(a_2)...F(a_n))
]
答案对(1e9+7)取模。
其中(F(i))表示斐波那契数列第 (i) 项。
( m Sol:)
我们应当注意到一个这样的基本事实:
考虑到( m lcm)可以看作对于因数分解下的每一位取(max),而(gcd)则可以看作对因数分解下的每一位取(min)
于是我们会发现在我们一无所知的情况下我们所求的( m lcm)和(gcd)居然可以通过(min -max)容斥处理。
具体来说是因为( m lcm)看作指数取(max)而( m gcd)看作指数取(min)所以我们会发现其相当于对于指数做一个(min-max)容斥即可。
然后我们发现每个因数的贡献是乘起来的,所以我们得到:
[ ext{lcm}(S)=prod_{Tsub S}gcd(T)^{(-1)^{|T|+1}}
]
这个式子丢到指数上一看就能明白正确性了(
然后又因为对于斐波那契数列而言,存在:(gcd(f(a),f(b))=f(gcd(a,b)))
于是我们所求为:
[prod_{Tsub S}f(gcd(a...))^{(-1)^{|T|+1}}
]
注意到值域并不大,我们考虑莫比乌斯反演,考虑化简原式应当为:
[prod_{i=1}^{10^6} f(i)^{[gcd_{iin T}(a_i)==i](-1)^{(|T|+1)}}
]
我们考虑统计上式,不妨令(F(x))表示(gcd) 至少是(x)的指数贡献和
初步考虑后注意到对于(F(x)),假定有(k)个(i)满足(x|a_i),则可知(F(x))为:
[sum_{i=1}^{k}dbinom{k}{i}(-1)^{|i|+1}
]
注意到这个式子的值恒定为:([k e 0])
然后我们令(g(i))表示恰好
则可得:
[F(x)=sum_{x|d}g(d)
]
[g(d)=sum_{d|x}mu(frac{x}{d})F(x)
]
直接反演即可。
注意到答案肯定很小,我们甚至不需要使用欧拉定理。
然后这道题的斐波那契数列实际上是当作(f_1=1,f_2=1)这样推的= =,这一点破坏了这道题的和谐美感。
(Code:)
#include<bits/stdc++.h>
using namespace std ;
#define rep( i, s, t ) for( register int i = s; i <= t; ++ i )
#define re register
#define int long long
int gi() {
char cc = getchar() ; int cn = 0, flus = 1 ;
while( cc < '0' || cc > '9' ) { if( cc == '-' ) flus = - flus ; cc = getchar() ; }
while( cc >= '0' && cc <= '9' ) cn = cn * 10 + cc - '0', cc = getchar() ;
return cn * flus ;
}
const int M = 1e6 + 5 ;
const int N = 1e5 + 5 ;
const int P = 1e9 + 7 ;
int n, m, a[N], mu[M], p[N], f[M], F[M], Ans, top ;
bool isp[M], cnt[M] ;
void init( int x ) {
f[2] = f[1] = 1, mu[1] = 1, isp[1] = 1 ;
for( re int i = 2; i <= x; ++ i ) {
if( i != 2 ) f[i] = ( f[i - 1] + f[i - 2] ) % P ;
if( !isp[i] ) p[++ top] = i, mu[i] = -1 ;
for( re int j = 1; j <= top && p[j] * i <= x; ++ j ) {
isp[p[j] * i] = 1 ;
if( i % p[j] == 0 ) break ;
mu[i * p[j]] = - mu[i] ;
}
}
}
int fpow( int x, int k ) {
int ans = 1, base = x ;
while( k ) {
if( k & 1 ) ans = ans * base % P ;
base = base * base % P, k >>= 1 ;
} return ans % P ;
}
signed main()
{
n = gi(), init(1e6), Ans = 1 ;
rep( i, 1, n ) a[i] = gi(), cnt[a[i]] = 1, m = max( m, a[i] ) ;
for( re int i = 1; i <= m; ++ i )
for( re int j = i; j <= m; j += i ) cnt[i] |= cnt[j] ;
for( re int i = 1; i <= m; ++ i )
for( re int j = i; j <= m; j += i ) F[i] += mu[j / i] * cnt[j] ;
for( re int i = 1; i <= m; ++ i ) {
if( F[i] > 0 ) Ans = ( Ans * fpow( f[i], F[i] ) % P ) ;
if( F[i] < 0 ) Ans = ( Ans * fpow( fpow( f[i], -F[i] ), P - 2 ) ) % P ;
}
printf("%lld
", Ans ) ;
return 0 ;
}