题目大意:
有K个蓝球,N-K个红球。这些球排成一行,小明每次收集连续子串的蓝球,现在有K个query,第ith query问的是若小明用i步把蓝球收集完,则这样的球的排列方式有多少种。
题解:
排列组合题目,首先我们假设有X1种排列红球的方法,有X2种排列蓝球的方法。那么本次query有X1 * X2种排列方法。所以问题转化为怎么算X1和X2. 首先看蓝球。蓝球每次query询问相当于分成了i堆,那么每堆分配多少个蓝球对应不同的排列方法。假设把蓝球放成一行,那么其中有K-1个空隙,分成i堆,相当于有i-1个隔板在中间,则隔板的位置总共有多少种放法对应于X2。所以X2=。这时候我们看X1的求法,假设我们把红色球放成一行,红球的空隙加上两边总共有N-K+1个,我们定义这个叫红球空档。 这时候X1等于蓝色球的i堆 放在这些空档有几种放法。X1=
,其中的组合数可以用pascal 三角形来算复杂度O(n^2),具体的板子可以看https://www.geeksforgeeks.org/calculate-ncr-using-pascals-triangle/
另外!这里的数字比较大,所以记住组合数计算的时候需要模一下!
AC代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
// Initialize the matrix with 0
const int MAXN =2e3+10;
const int MAXR =2e3+10+10;
const int MODN=1e9+7;
int l[MAXN][MAXR] = { 0 };
void initialize()
{
// 0C0 = 1
l[0][0] = 1;
for (int i = 1; i < MAXN; i++) {
// Set every nCr = 1 where r = 0
l[i][0] = 1;
for (int j = 1; j < i + 1; j++) {
// Value for the current cell of Pascal's triangle
l[i][j] = (l[i - 1][j - 1] + l[i - 1][j])%MODN;
}
}
}
// Function to return the value of nCr
int nCr(int n, int r)
{
// Return nCr
return l[n][r];
}
int32_t main(){
int n,k;
initialize();
cin>>n>>k;
for(int sta=1;sta<=k;sta++){
cout<<(nCr(k-1,sta-1)*nCr(n-k+1,sta))%MODN<<endl;
}
}