AtCoder Beginner Contest 167 E:Colorful Blocks 組合數/DP分析

我們先DP分析

dp[i][j]表示,按從左往右的順序填到i時,有j對相鄰數字不同,的方案數

顯然:dp[i][j]=dp[i-1][j]*(m-1)+dp[i-1][j-1];

我們把DP在紙上推演如下:

發現:每個i所在行的d[pi][j]其實就是二次項展開的一項

dp[n][j]=m*C_{n-1}^j*(m-1)^{n-i-1}

求和dp[n][0]到dp[n][k]即可。

 

第二種思路是用組合數直接進行分析:

考慮:n個數,k個相鄰位置數相同,

我們在n-1個空位中選擇k個位置,使得k左右數相同。

然後固定最左邊的數,有m種選法,依次往右選,遇到剛纔選出的位置,選法只有一種。

其餘都是m-1種選法。

綜上方案數爲:m*C_{n-1}^j*(m-1)^{n-i-1}

同樣求和即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 2e5+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y){ee[++cnt].nxt=head[x],ee[cnt].to=y,head[x]=cnt;}
*/
const int mod = 998244353;
ll qpow (ll a,ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1)ans=ans*a%mod;
		a=a*a%mod;
		b/=2;
	}
	return ans;
}
ll fac[M],inv[M],p[M];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	ll n,m,k;
	cin>>n>>m>>k;
	fac[0]=p[0]=inv[0]=1;
	for(int i=1;i<=200000;i++)fac[i]=fac[i-1]*i%mod,p[i]=p[i-1]*(m-1)%mod;;
	inv[200000]=qpow(fac[200000],mod-2);
	for(int i=200000-1;i;i--)inv[i]=inv[i+1]*(i+1)%mod;
	ll ans=0;
	for(int i=1;i<=k;i++)
	{
		ll C=fac[n-1]*inv[i]%mod*inv[n-1-i]%mod;
		ans=(ans+m*p[n-i-1]%mod*C%mod)%mod;
	}
	ans=(ans+m*p[n-1]%mod)%mod;
	cout<<ans<<endl;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章