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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值