1. 程式人生 > >Avito Cool Challenge 2018:C. Colorful Bricks

Avito Cool Challenge 2018:C. Colorful Bricks

C. Colorful Bricks

題目連結:https://codeforces.com/contest/1081/problem/C

題意:

有n個橫向方塊,一共有m種顏色,然後有k個方塊的顏色與其左邊的顏色不同(第一個除外),問一共有多少染色方案。

 

題解:

我們首先來考慮一下dp。

設dp(i,j)為當前第i個方塊,一共有j個方塊與它前面的方塊不同的方案個數。

那麼轉移方程為dp(i,j)=dp(i-1,j-1)*(m-1)+dp(i-1,j)。

 

程式碼如下:

#include <bits/stdc++.h>
using
namespace std; typedef long long ll; const int MOD = 998244353,N = 2005; ll n,m,k; ll dp[N][N]; int main(){ cin>>n>>m>>k; dp[1][0]=m; for(int i=2;i<=n;i++){ for(int j=0;j<i;j++){ dp[i][j]=dp[i-1][j]; if(j!=0) dp[i][j]=(dp[i][j]+dp[i-1
][j-1]*(m-1))%MOD; } } cout<<dp[n][k]; return 0; }
View Code

 

還有一種數學的計數方法。

我們假設已經選定了k種顏色,除開第一個,那麼我們就可以直接把2-n的位置進行縮點,縮成有前一個的顏色不等於後一個顏色的點(因為有一些點的顏色是和之前的點顏色相等的,這種對答案沒有貢獻,取決於之前的那個顏色)。

然後第一個位置有m種情況,之後的每個位置都有m-1種情況。

所以最後答案為C(n-1,k)*m*(m-1)^k。

 

程式碼如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 998244353 ,N = 2005;
ll n,m,k;
ll C[N][N];
ll qp(ll a,ll b){
    ll ans = 1;
    while(b){
        if(b&1) ans=(a*ans)%MOD;
        a=(a*a)%MOD;
        b>>=1;
    }
    return ans ;
}
int main(){
    cin>>n>>m>>k;
    C[0][0]=C[1][1]=1;
    for(int i=1;i<=n;i++) C[i][0]=1;
    for(int i=2;i<=n;i++)
        for(int j=1;j<=i;j++)
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD;
    ll ans = (C[n-1][k]*m)%MOD;

    cout<<ans*qp(m-1,k)%MOD<<endl;
    return 0;
}
View Code