C. Colorful Bricks (组合数学/dp)

给你n个方格排成一行,有m种颜色,然后要把这n个方格分成k+1段,每段涂不同的颜色,问有多少种方法。
排列组合问题,首先要在n-1个位置里面选出k个位置当作段与段的分割点,然后每段涂的时候有m*(m-1)^k种,二者相乘即使答案。
要注意的是计算组合数的时候也要取mod,因为组合数的增加也是很快的。
还有要上快速幂计算

所以C(n-1,k)m(m-1)^k。注意取模。

#include
#include
#include
 
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
#include
#include
 
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;
}

你可能感兴趣的:(codeforces,victor的DP专练,victor的数学(技巧)专练)