您的位置:首页 > 大数据 > 人工智能

hdu 5407 CRB and Candies(组合数+最小公倍数+素数表+逆元)2015 Multi-University Training Contest 10

2015-08-21 17:00 267 查看
题意:

输入n,求c(n,0)到c(n,n)的所有组合数的最小公倍数。

输入:

首行输入整数t,表示共有t组测试样例。

每组测试样例包含一个正整数n(1<=n<=1e6)。

输出:

输出结果(mod 1e9+7)。

感觉蛮变态的,从比赛开始我就是写的这道题,比赛结束还是没写出来……

期间找到了逆元,最小公倍数,组合数的各种公式,但是爆了一下午tle。

比赛结束,题解告诉我,公式秒杀法……

但是公式看不懂,幸好有群巨解说,所以有些听懂了,但还是需要继续思考才能弄懂。

题解:

设ans[i]表示i的所有组合数的最小公倍数。

设f[i]表示从1到i的正整数的最小公倍数。

然后获得从f[i]到ans[i]的公式——ans[i] = f[i+1]/i。 anss[i-1] = (f[i]*inv[i])%Mod;

然后获得求f[i]的公式——

  if(i == p^k) f[i] = f[i-1]*p;

  else f[i] = f[i-1];

接下来需要做的就是找到那些i == p^k了。

解题步骤:

1. 打素数表;

2. 由素数表寻找i == p^k;

3. f[1] = 1,打f[]数组表和ans[]数组表;

4. 输入数据;

5. 根据输入数据和ans[]表输出答案。

我认为还有其他方法,因为ac的程序的运行时间从15ms到900+ms都有。更多方法持续寻找中。

我的(根据题解的)代码——

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;

#define LL long long
const int N = 1000010;
const int Mod = 1000000007;

int n, t;
LL ans, mid;
LL inv
;
LL anss
;
bool su2
;
int su
, su1
;
LL f
;                                                    //f[i]表示1~i的最小公倍数

void table()
{
inv[1] = 1;
for(int i = 2; i < N; i++)                              //求i的逆元
{
inv[i] = inv[Mod%i]*(Mod-Mod/i) % Mod;
}

memset(su2, 1, sizeof(su2));
memset(su1, 0, sizeof(su1));
su2[0] = su2[1] = 0;                                    //求N以内的素数
su2[2] = 1;
for(int i = 3; i < N; i++) su2[i] = i%2 == 0 ? 0 : 1;
for(int i = 3; i <= sqrt(N*1.0); i++)
{
if(su2[i])
{
for(int j = i*i; j <= N; j += 2*i)
{
su2[j] = 0;
}
}
}
int k = 0;
for(int i = 0; i < N; i++)                              //打N以内的素数表
{
if(su2[i] == 1) su[k++] = i;
}
for(int i = 0; i < k; i++)                              //寻找满足p^k的数,其中p为素数,k为正整数
{
LL mid = su[i];
while(mid < N)
{
su1[mid] = su[i];
mid *= su[i];
}
}
f[1] = 1;                                               //打N以内的1~i的最小公倍数表
for(int i = 2; i < N; i++)
{
if(su1[i]) f[i] = f[i-1]*su1[i];
else f[i] = f[i-1];
f[i] %= Mod;
anss[i-1] = (f[i]*inv[i])%Mod;                      //答案表
}
}

int main()
{
//freopen("test.in", "r", stdin);
//freopen("test.out", "r", stdout);
table();
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
printf("%I64d\n", anss
);
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: