2015-06-26 21:43:37
【传送门】
总结:这场做出了两题,都是数学类的,速度还可,回到黄咯~
反思:第一题没看到数据范围,用了比较麻烦的逆元预处理。第二题纠结题意过久。第三题思维不够强,没想到....
A题:组合数
题意:有 k 种颜色的球,颜色号分别为1~k,每种球 ci 个(1 <= k,c <= 1000),让排成一排,使得第 i 种颜色的最后一个球必须在第 i-1 种颜色的最后一个球的后面,问有多少种这样的排列。
思路:从末尾往前面的考虑,最后一个位置必定放第 k 种颜色的球,那么该种颜色剩下的 ck-1 个球就随便放了,有 C(n-1,ck-1)种,这样剩下 n - ck 个位置,再考虑第 k-1 种颜色的球,以此类推即可。就是:C(n-1,ck-1) * C(n-ck-1,c(k-1) - 1) * ....
#include <cstdio> #include <ctime> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define getmid(l,r) ((l) + ((r) - (l)) / 2) #define MP(a,b) make_pair(a,b) #define PB(a) push_back(a) typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int INF = (1 << 30) - 1; const ll mod = 1000000007LL; const int MAXN = 1000000; int k,c[1010],sum; ll fac[MAXN + 10],afac[MAXN + 10]; ll Q_pow(ll x,ll y){ x %= mod; ll res = 1; while(y){ if(y & 1) res = res * x % mod; x = x * x % mod; y >>= 1; } return res; } void Pre(){ fac[0] = afac[0] = 1; for(int i = 1; i <= MAXN; ++i) fac[i] = fac[i - 1] * (ll)i % mod; afac[MAXN] = Q_pow(fac[MAXN],mod - 2); for(int i = MAXN; i >= 1; --i) afac[i - 1] = afac[i] * i % mod; } ll C(int n,int m){ if(m > n) return 0; return fac[n] * afac[n - m] % mod * afac[m] % mod; } int main(){ Pre(); sum = 0; scanf("%d",&k); for(int i = 1; i <= k; ++i){ scanf("%d",&c[i]); sum += c[i]; } ll ans = 1; for(int i = k; i >= 1; --i){ ans = ans * C(sum - 1,c[i] - 1) % mod; sum -= c[i]; } printf("%I64d\n",ans % mod); return 0; }