Atcoder E - Roaming

题意:
n n n个房间,编号为 1 , 2 , 3 , 4.... n 1,2,3,4....n 1,2,3,4....n,每个房间里有一个人,然后接下来有 k k k步,每一步都可以有一个人从一个房间到另外一个房间,问你经过 k k k步后有多少种排列方式。
思路:
首先可以肯定的是,一个人从一个房间出来,然后那个房间人数为0,然后另外一个人也从房间出来,只能到有人的房间,不能到没有人的房间,否则,又回到了第一步,没有意义。
我们经过 k k k步,会有 k k k个房间人数为0,但是要注意的是 n n n个房间无论经过多少步,都会至少有一个房间里有人。
S o So So
a n s = ∑ i = 1 m i n ( k , n − 1 ) C n i ⋅ C n − 1 i ans=\sum\limits_{i=1}^{min(k,n-1)}C_n^i\cdot C_{n-1}^i ans=i=1min(k,n1)CniCn1i

解释一下,每步从n个房间里取 i i i个人,那么会有 i i i个房间为空,所以就是 n n n个人分配给 n − i n-i ni个房间。用隔板法, n n n个人之间可以插入 n − 1 n-1 n1个隔板,然后要分到 n − i n-i ni个房间去,就是要插入 n − i − 1 n-i-1 ni1个隔板,又因为 C n − 1 n − i − 1 = C n − 1 i C_{n-1}^{n-i-1}=C_{n-1}^i Cn1ni1=Cn1i,所以答案如上。

ll fac[N];
ll Qpow(ll a,ll b,ll p){
    a = (a%p+p)%p;
    ll ans = 1;
    while(b){
        if(b&1) ans = ans * a % p;
        b >>= 1;
        a = a * a % p;
    }
    return ans;
}
ll C(ll n,ll m){
    return fac[n]*Qpow(fac[n-m]*fac[m]%mod,mod-2,mod)%mod;
}
void init(ll n){
    fac[0] = 1;
    rep(i,1,n){
        fac[i] = fac[i-1] * i%mod;
    }
}
int main(){
    int n = read(),k = read();
    init(N-10);
    k = min(k,n-1);
    ll ans = 0;
    rep(i,1,k){
        ans += C(n,i)*C(n-1,i)%mod;
        ans %= mod;
    }
    printf("%lld",(ans+1)%mod);
}

你可能感兴趣的:(组合数学)