LightOJ 1226

**题意:**按要求完成n个任务,每个任务必须进行a[i]次才算完成,且按要求,第i个任务必须在大于i任务完成之前完成,问有多少种完成顺序的组合。(n<=1000 a[i] <= 1e6 mod = 1e9+7) **思路:**组合问题,从任务序号低的开始完成,由于必须使序号高的在后,所以必定在末尾的数字是高序号的,那么对剩余的a[i]-1个数字进行插空法,一个序号有C(cnt+a[i]-1,a[i]-1)种,剩下的就是Lucas定理了(数据小不用也能过),但是要注意预处理出逆元,不然会TLE。
/** @Date    : 2016-11-21-18.26
* @Author : Lweleth (SoungEarlf@gmail.com)
* @Link : https://github.com/
* @Version :
*/
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <utility>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <stack>
#include <queue>
//#include<bits/stdc++.h>
#define LL long long
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const LL mod = 1000000007;

LL inv[N*10], fa[N*10];

LL fpow(LL a, int n)
{
LL r = 1;
while(n > 0)
{
if(n & 1)
r = r * a % mod;
a = a * a % mod;
n >>= 1;
}
return r;
}
void init()
{
fa[0] = 1;
inv[0] = 1;
for(LL i = 1; i <= 1000100; i++)
{
fa[i] = fa[i-1] * i % mod;
inv[i] = fpow(fa[i], mod - 2);
}
}

LL C(LL n, LL m)
{
if(m > n)
return 0;
LL ans = 0;
ans = ((fa[n] * inv[m] % mod)* inv[n-m]) % mod;
return ans;
}

LL lucas(LL n, LL m)
{
if(m == 0)
return 1;
return C(n % mod, m % mod) * lucas(n / mod, m / mod) % mod;
}
LL a[1100];
int main()
{
int T;
cin >> T;
init();
int cnt = 0;
while(T--)
{
LL n;
scanf("%lld", &n);
for(int i = 1; i <= n; i++)
scanf("%lld", a + i);
LL ans = 1;
LL ct = 0;
for(int i = 1; i <= n; i++)
{
ct += a[i];
ans = (ans*lucas(ct-1, a[i]-1) % mod);
}
printf("Case %d: %lld ", ++cnt, ans);
}
return 0;
}

原文地址:https://www.cnblogs.com/Yumesenya/p/6086796.html