HDU 5407 CRB and Candies(素数筛 + 逆元 + 组合数公式)——2015 Multi-University Training Contest 10

227 篇文章 0 订阅
97 篇文章 0 订阅

传送门

CRB and Candies

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1049    Accepted Submission(s): 501


Problem Description
CRB has N different candies. He is going to eat K candies.
He wonders how many combinations he can select.
Can you answer his question for all K (0 ≤ K N )?
CRB is too hungry to check all of your answers one by one, so he only asks least common multiple(LCM) of all answers.
 

Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case there is one line containing a single integer N .
1 ≤ T ≤ 300
1 ≤ N 106
 

Output
For each test case, output a single integer – LCM modulo 1000000007( 109+7 ).
 

Sample Input
  
  
5
1
2
3
4
5
 

Sample Output
  
  
1
2
3
12
10
 

Author
KUT(DPRK)

题目大意:

有一个小孩儿,他有 n 块不同的糖,然后他想吃 k (kn) 块,然后有多少种不同的方法可以吃到 k 块,现在问你的是所有的吃 k (0kn)

块糖的不同方法的最小公倍数。

解题思路:

首先根据题意列出一个公式: ans = LCM(C(n,0),C(n,1)...C(n,n)) ,然后这个公式可以化为: ans = LCM(1,2,...,n+1)(n+1)

然后通过这个公式就可以求了,求最小公倍数可以通过素因子分解来计算其实我们可以发现一个规律,举个例子 当 n = 10 的时候:

1 = 1
2 = 2
3 = 3
4 = 22
5 = 5
6 = 23
7 = 7
8 = 23
9 = 32
10 = 25
然后计算 LCM(1,2,...,10) 其实就是主要计算素因子的个数,我们取的是素因子的指数最大的那个数,那么其实我们可以将其化为下列这样的式子:

1 = 1
2 = 2
3 = 3
4 = 2
5 = 5
6 = 0
7 = 7
8 = 2
9 = 3
10 = 0

所以 LCM(1,2,...,10) 就等于上述式子的乘积(不算 0 ),那么这样就可以计算了,首先进行素数筛,将 1106 之间的素数全部筛选出来,然后计算答案的分子的时候,

就是类似上面那样计算的,分母可以实现预处理保存在一个数组(也就是逆元数组 Inv )里,这里需要注意的是不能直接计算 LCM(1,2,...,n+1) 因为有取模,直接计算的就会错,

当然可以用高精度试一试,我没有试不知道到底可不可行。

My Code

/**
2016 - 09 - 02 下午
Author: ITAK

Motto:

今日的我要超越昨日的我,明日的我要胜过今日的我,
以创作出更好的代码为目标,不断地超越自己。
**/

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int INF = 1e9+5;
const int MAXN = 1e6+5;
const LL MOD = 1e9+7;
const double eps = 1e-7;
const double PI = acos(-1);
using namespace std;
LL Scan_LL()///输入外挂
{
    LL res=0,ch,flag=0;
    if((ch=getchar())=='-')
        flag=1;
    else if(ch>='0'&&ch<='9')
        res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+ch-'0';
    return flag?-res:res;
}
int Scan_Int()///输入外挂
{
    int res=0,ch,flag=0;
    if((ch=getchar())=='-')
        flag=1;
    else if(ch>='0'&&ch<='9')
        res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+ch-'0';
    return flag?-res:res;
}
void Out(LL a)///输出外挂
{
    if(a>9)
        Out(a/10);
    putchar(a%10+'0');
}
void Exgcd(LL a, LL b, LL &x, LL &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return;
    }
    LL x1, y1;
    Exgcd(b, a%b, x1, y1);
    x = y1;
    y = x1 - (a/b)*y1;
}
LL Inv[MAXN];
void Init()
{
    Inv[1] = 1;
    for(int i=2; i<MAXN; i++)
    {
        LL x, y;
        Exgcd((LL)i, MOD, x, y);
        x = (x%MOD+MOD)%MOD;
        Inv[i] = x;
    }
}
int cnt = 0;
LL p[MAXN];
bool prime[MAXN];
void isprime()
{
    memset(prime, 0, sizeof(prime));
    cnt = 0;
    for(int i=2; i<MAXN; i++)
    {
        if(!prime[i])
        {
            p[cnt++] = i;
            for(int j=i+i; j<MAXN; j+=i)
                prime[j] = 1;
        }
    }
}
LL lcm[MAXN], vis[MAXN];
void Pre()
{
    lcm[1] = 1;
    memset(vis, 0, sizeof(vis));
    for(int i=0; i<cnt; i++)
    {
        LL tmp = p[i];
        while(tmp < MAXN)
        {
            vis[tmp] = p[i];
            tmp *= p[i];
        }
    }
    for(int i=2; i<MAXN; i++)
    {
        if(vis[i])
            lcm[i] = (lcm[i-1]*vis[i])%MOD;
        else
            lcm[i] = lcm[i-1]%MOD;
    }
}
int main()
{
    Init();
    isprime();
    Pre();
    int T, n;
    while(~scanf("%d",&T))
    {
        while(T--)
        {
            n = Scan_Int();
            LL ans = (Inv[n+1]*lcm[n+1])%MOD;
            cout<<ans<<endl;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值