1. 程式人生 > >[Codeforces37D]Lesson Timetable

[Codeforces37D]Lesson Timetable

題目大意

有m個教室,第i個教室最多能容納Yi組人,初始時第i個教室有Xi組人。
現在每組人要從當前所在的教室a移動到教室b(a≤b)。我們不知道第i組人初始在哪間教室,以及它要去哪間教室,求可能的方案數。答案對109+7取模

資料範圍

1≤m≤100 0<Xi≤1000 0≤Xi,Yi≤100

思路

設s[i]=ij=1xj
先無視每個組的編號,然後設f[i][j]為初始前i個教室,已經分配了j組人的新教室,方案數為多少。轉移顯然:

f[i][j]=f[i1][jk]Cks[i](jk)
其中k列舉的是放在教室i的組數,注意0≤k≤Y[i]。

那麼f[m][s[m]]就是要求的答案了。加上每組人編號的影響:

ans=f[m][s[m]]i=1mCX[i]s[m]s[i1]
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int mo=1e9+7;

int n,m,s[105],f[105][1005],Fact[1005],Ie[1005],X[105],Y[105];

int quick(int x,int y)
{
    if (!y) return 1;
    int tmp=quick(x,y/2
); tmp=(LL)tmp * tmp % mo; if (y % 2==1) tmp=(LL)tmp*x % mo; return tmp; } int C(int n,int m) { return (LL)Fact[n] * Ie[m] % mo * Ie[n-m] % mo; } int main() { scanf("%d",&m); for (int i=1;i<=m;i++) { scanf("%d",&X[i]); s[i]=s[i-1]+X[i]; } n=s[m]; for
(int i=1;i<=m;i++) scanf("%d",&Y[i]); Fact[0]=Ie[0]=1; for (int i=1;i<=n;i++) { Fact[i]=(LL)Fact[i-1]*i % mo; Ie[i]=quick(Fact[i],mo-2); } f[0][0]=1; for (int i=1;i<=m;i++) { for (int j=0;j<=s[i];j++) { for (int k=0;k<=min(j,Y[i]);k++) { f[i][j]=(f[i][j]+(LL)f[i-1][j-k] * C(s[i]-j+k,k) % mo) % mo; } } } int ans=f[m][n]; for (int i=1;i<=m;i++) ans=(LL)ans * C(n-s[i-1],X[i]) % mo; printf("%d\n",ans); return 0; }