HDU 5407 CRB and Candies(数论+yy)

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(n1)p.
否则 g(n)=g(n1).
所以我们可以先筛出素数表,然后预处理出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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值