码迷,mamicode.com
首页 > 其他好文 > 详细

Leftmost Ball

时间:2020-01-19 17:46:15      阅读:86      评论:0      收藏:0      [点我收藏+]

标签:long   spl   ret   amp   就会   fine   put   i+1   define   

题目链接:Click here

Solution:

我们把问题转化一下,改成可以放白球和其他颜色的球

那么对于一种合法的方案,显然有它的任意一个前缀的白球数大于等于其他颜色数

那么,我们考虑设\(f[i][j]\)表示已经放了\(i\)个白球,刚好放完了\(j\)种颜色的方案数

考虑有两种转移,一种是我们再放一个白球,或者再加入一种颜色

这里我们钦定接下来放的第一个球一定在第一个空缺的位置,否则就会算重

那么转移就是这样的:
\[ f[i][j]=f[i-1][j]+f[i][j-1]\times {(k-1)\times (n-j+1)+n-i-1 \choose k-2} \]
需要注意的是,当\(k=1\)时,我们需要给出特判,并且我们在\(dp\)时是没有考虑颜色的排列顺序的,所以最后要乘上阶乘

Code:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e3+11;
const int M=4e6+11;
const int mod=1e9+7;
int n,k,f[N][N],fac[M],ifac[M];
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;
}
int qpow(int a,int b){
    int re=1;
    while(b){
        if(b&1) re=(re*a)%mod;
        b>>=1;a=a*a%mod;
    }return re;
}
int C(int a,int b){
    if(a<b) return 0;
    return fac[a]*ifac[b]%mod*ifac[a-b]%mod;
}
signed main(){
    n=read(),k=read();
    if(k==1) return puts("1"),0;
    fac[0]=1;ifac[0]=1;f[0][0]=1;
    for(int i=1;i<=n*k;i++) fac[i]=fac[i-1]*i%mod;
    ifac[n*k]=qpow(fac[n*k],mod-2);
    for(int i=n*k-1;i;i--) ifac[i]=ifac[i+1]*(i+1)%mod;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=i;j++){
            if(i>j) f[i][j]+=f[i-1][j];
            f[i][j]=(f[i][j]+f[i][j-1]*C((n-j+1)*(k-1)+n-i-1,k-2)%mod)%mod;
        }
    printf("%lld\n",f[n][n]*fac[n]%mod);
    return 0;
}

Leftmost Ball

标签:long   spl   ret   amp   就会   fine   put   i+1   define   

原文地址:https://www.cnblogs.com/NLDQY/p/12214807.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!