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; }
还有一种数学的计数方法。
我们假设已经选定了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; }
重要的是自信,一旦有了自信,人就会赢得一切。