版权声明:转载注明下出处就行了。 https://blog.csdn.net/LJD201724114126/article/details/85055904
题目链接:https://codeforces.com/contest/1081/problem/C
题意:给n,m,k,用m中颜色给1*n的方块涂色,满足有k个小方块与其左边是不同的(除开第一个),求出涂色方案数。
题解:参考官方题解。
解法一:
我们可以在n-1块方块选择k个方块,来涂色,满足其与左边不同,即是,
我们来解释下,先选出k个,然后首先第一个可以取m种颜色,相对应的其它k个每个方块都能取m-1种颜色。
假设我们选好了第一块的颜色,那么要是下一个不是选出k个的其中一个,其颜色一定与第一块相同,要是在选出k个中的其中一个,那么我们要满足这两个不同,只能有m-1中颜色可以选择。以此类推。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxn=2010;
const LL mod=998244353;
LL jie[maxn],ni[maxn];
LL fast_pow(LL a,LL n)
{
LL sum=1;
while(n)
{
if(n&1) sum=sum*a%mod;
a=a*a%mod;
n/=2;
}
return sum;
}
void init()
{
jie[0]=jie[1]=1;
for(int i=2;i<maxn;i++)
jie[i]=1LL*jie[i-1]*i%mod;
ni[2000]=fast_pow(jie[2000],mod-2);
for(int i=2000;i>=1;i--) ///费马小定理线性筛阶乘逆元
{
ni[i-1]=1LL*ni[i]*i%mod;
}
}
int main()
{
LL n,m,k;
init();
while(~scanf("%lld%lld%lld",&n,&m,&k))
{
printf("%lld\n",jie[n-1]*ni[k]%mod*ni[n-1-k]%mod*m%mod*fast_pow(m-1,k)%mod);
}
return 0;
}
解法二:
我们设dp[n][m] 表示在1到n个方块中,有m个小方块与其左边的颜色不同,那么我们考虑第i个小方块颜色与第i-1块小方块颜色是否相同
即:dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*(m-1)。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxn=2010;
const LL mod=998244353;
LL dp[maxn][maxn];
int main()
{
int n,m,k;
while(~scanf("%d%d%d",&n,&m,&k))
{
dp[1][0]=m;
for(int i=1;i<n;i++)
{
for(int j=0;j<=k;j++)///转移方程不一定非要按照说的去,也可以变下,本质上也是相同的
{
dp[i+1][j]=dp[i+1][j]+dp[i][j]%mod;
dp[i+1][j+1]=(dp[i+1][j+1]+dp[i][j]*(m-1)%mod)%mod;
}
}
printf("%lld\n",dp[n][k]%mod);
}
return 0;
}