HDU 5407
题意:
计算:
LCM(C0N,C1N,C2N,...,CNN)(1<=N<=106)
思路:
先打个表看看?
我们可以发现:
f(3)=f(4)/4,f(5)=f(6)/6,
f(9)=f(10)/10,f(11)=f(12)/12
f(15)=f(16)/16,f(17)=f(18)/18
这个迷之规律会在什么时候出现呢?“远离”单个素数幂的时候。
而素数幂会对什么造成影响呢?结合题目,应该是前n个数的LCM。
所以,规律就是
f(n)=LCM(1,2,3,4,5,..,n+1)n+1
这里放上严格证明:
(http://www.zhihu.com/question/34859879/answer/60168919)
那么如何计算f(n)呢?
我们设
g(n)=LCM(1,2,3,..,n)
如果
n=pk,g(n)=g(n−1)∗p.
否则
g(n)=g(n−1).
所以我们可以先筛出素数表,然后预处理出g(n),然后便可在
O(1)
的时间内实现查询。
计算f(n)的时候不能直接除以(n+1),应乘以其逆元.
总复杂度:
预处理:
筛素数 + 求g(n) :
O(nlogn)
查询:
O(1)
。
代码:
/*
* @author FreeWifi_novicer
* language : C++/C
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
using namespace std;
#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;
const int maxn = 1000000 + 10 ;
bool isprime[maxn] ;
lint lcm[maxn] ;
lint f[maxn] ;
vector<lint>p ;
const int mod = 1e9 + 7 ;
void sieve(){
clr( isprime , true ) ;
for( lint i = 2 ; i * i <= maxn ; i++ ){
if( isprime[i] )
for( lint j = i * i ; j <= maxn ; j += i )
isprime[j] = false ;
}
for( lint i = 2 ; i <= maxn ; i++ )
if( isprime[i] )
p.pb( i ) ;
}
void init_lcm(){
sieve() ;
vector<lint>:: iterator it ;
for( lint i = 1 ; i <= maxn ; i++ ) lcm[i] = 1 ;
for( it = p.begin() ; it != p.end() ; it++ ){
for( lint j = *it ; j <= maxn ; j = *it * j ){
lcm[j] = *it ;
}
}
f[1] = 1 ;
for( lint i = 2 ; i <= maxn ; i++ ) f[i] = f[i-1] * lcm[i] % mod ;
}
lint fast_pow( lint x , lint n ){
lint res = 1 ;
while( n ){
if( n & 1 )
res = res * x % mod ;
n >>= 1 ;
x = x * x % mod ;
}
return res ;
}
void solve( lint n ){
n++;
lint x = fast_pow( n , mod - 2 ) ;
lint ans = f[n] * x % mod ;
cout << ans << endl;
}
int main(){
// freopen("input.txt","r",stdin);
int t ; cin >> t ;
init_lcm() ;
while( t-- ){
lint n ;
cin >> n ;
solve( n ) ;
}
return 0;
}