洛谷AT2000左端ボール

トピックリンク

私たちは、データ範囲を必要と知らせる(O(N ^ 2)\ )\ レベルのアプローチ

まず、簡単なDPの

ステップ1

\(DP [i]の[... ] \) 表現の前に\(I \)ボールの各色のボールと番号を入れて

列挙への最初のいくつかのボールは十分ではありませんので、明らかに私たちは、多くの完璧なソリューションを置くために各色のボールを記録しなければなりません

ステップ2

\(DP [..] \)どのように多くの各色のボールプットを表します

白いボールが容易にするためとデエンファシスの中で最も左側の同じ色のボールが、あるので、我々は最初の空席に左から右にそれぞれ白いボールは、他の自由にボールZhaokongです考えます

我々が想定しているため、すべてのボールが異なる、そして最後で割ったです((K-1)\ \ ) ボールに配置します

ステップ3

\(DP [i]は[J ] \) 現在のプットを表す\(I \)白いボール、\(J \)色のボールを

白いボールは、ボールの前の同じ色でなければならないため

私たちは、白いボールを入れて、他のボールは、別個に

異なる色のボールは、我々は現在の方法からの放電は、残りのスペースを見つけることであることが判明\((K-1)\ ) 空の数の組み合わせ

あなたが考えることができるようにそれぞれ1個の色のボールを入れて

操作の各配列について、又は白いボールを置くために、または色\(K-1 \)全てにボール

繰り返しを避けるために、我々は右の最初の空の位置にボールを置くために残っているものだけ考えるたびに、

\ [Dpを[I] [J ] = DP [I-1]〜[J] + DP [I]、[J-1] *(N-J + 1)* C_ {N * K-(J-1)* (K-1)-i-1
} ^ {K-2} \] 説明:

\(DP [I-1] [j]は\) 現在のプットに白いボールの転送を表し、

\(DP [I]、[J -1] *(N-J + 1)* C_ {N * K-(J-1)*(K-1)-i-1} ^ {K-2} \) 転送は、ボールを置くために現在の色を表し、

前記\(N-J + 1 \ ) ボールが空孔の上に置かれ、残りの色から選択された色を表します。

次に\(N * K-(J- 1)*(K-1)-i-1 \) で選択された空孔\(K-2 \) 2個のボール放電左

\(DP [I] [J ] \) ことを確実にする\(I> = jが\)意味があります

[コード]

#include<bits/stdc++.h>
using namespace std;

int read(){
    int x=0; char c=getchar(); int flag=1;
    while(!isdigit(c)) { if(c=='-') flag=-1; c=getchar(); }
    while(isdigit(c)) { x=((x+(x<<2))<<1)+(c^48); c=getchar(); }
    return x*flag;
}

const int mod=1e9+7;

int n,k;
int dp[2005][2005];//i个白球,j种颜色 

int fac[4000005],Inv[4000005]; 

int C(int n,int m){
    if(m<0||n<m) return 0;
    return 1ll*(1ll*fac[n]*Inv[m]%mod)*Inv[n-m]%mod; 
}

void exgcd(int a,int b,int &x,int &y){
    if(b==0) { x=1; y=0; return ; }
    exgcd(b,a%b,y,x); y-=a/b*x;
}

int inv(int a){
    int x=0,y=0;
    exgcd(a,mod,x,y);
    return (x%mod+mod)%mod;
}

signed main(){
    fac[0]=1;
    for(int i=1;i<=4000000;i++) fac[i]=1ll*fac[i-1]*i%mod;
    Inv[4000000]=inv(fac[4000000]);
    for(int i=3999999;i>=0;i--) Inv[i]=1ll*Inv[i+1]*(i+1)%mod;
    
    n=read(),k=read();
    if(k==1) { puts("1"); return 0; } 
    dp[0][0]=1;
    
    for(int i=1;i<=n;i++){ 
        dp[i][0]=1;
        for(int j=1;j<=i;j++){
            dp[i][j]=(dp[i-1][j]+1ll*(1ll*dp[i][j-1]*C(n*k-(j-1)*(k-1)-i-1,k-2))%mod*(n-j+1)%mod)%mod; 
        } 
    }
    
    printf("%d\n",dp[n][n]);
    return 0;
}

おすすめ

転載: www.cnblogs.com/zzhzzh123/p/12235545.html