E - Colorful Blocks
题意:
有 m 种颜色,给 n 个方块染色,可以不使用所有颜色,要求最多有 k 对相邻方块同色。问染色的总情况,最终结果模 998244353。
数据范围:
1 ≤ N, M ≤ 2×
0 ≤ K ≤ N − 1
思路:
观察样例中的112, 121……我们可以将 n 个方块按照颜色分成 t 组,连着的颜色相同的方块归为一组。如:112 中前两个方块是一组;第三个方块是第二组。然后我们可以惊奇地发现将 n 个方块分成t组后,同色的相邻方块的个数为 n - t 。
比如:n = 3,染色为 112 后,分成 2 组,相邻同色的方块有 n - t = 3 - 2 = 1 对。
根据题意要求相邻同色块最多有 k 对,所以 n - t ≤ k,n - k ≤ t ≤ n。枚举 t 的范围确定后,接下来确定如何将 n 个方块划分成 t 组:
我们设 t 个组包含的方块个数依次是 x1,x2,x3…… 。所以 x1+x2+x3+……+ = n 。用隔板法,有 n 个方块,在 n - 1 个位置中选择 t - 1 个位置放隔板,将 n 个方块分成 t 组,总共有 种选法法。对于每一种选法,先确定第一组的颜色,第一组是m种颜色任选一种都可,共m种选法;之后的第 2~t 组,每一组可选择的颜色是 m 种颜色中除上一组的颜色外的颜色,即每组有 m - 1 种选法,总共 t - 1 组,情况数为 。
总情况数为。
实现:
1. 求 ,用公式 。预处理出 n 范围内的所有阶乘以及阶乘的逆元
2. 用快速幂求
3. 注意取模
Code:
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
#define int long long
const int dx[] = { 1,-1,0,0 }, dy[] = { 0,0,1,-1 };
const int N = 200010, INF = 0x3f3f3f3f, mod = 998244353;
typedef pair<int, int>PII;
int n, m, k;
int fact[N], infact[N];
int mul(int x, int y)
{
return x * y % mod;
}
//快速幂
int qmi(int a, int k)
{
int res = 1;
while (k)
{
if (k & 1)res = res * a % mod;
a = a * a % mod;
k >>= 1;
}
return res;
}
//根据公式C(n,m)=n!/m!*(n-m)!
int C(int n, int m)
{
return fact[n] * mul(infact[m], infact[n - m]) % mod;
}
//预处理N范围内的所有阶乘和逆元
void init()
{
fact[0] = infact[0] = 1;
for (int i = 1; i <= n; i++)
{
fact[i] = fact[i - 1] * i % mod; //预处理阶乘
infact[i] = mul(infact[i - 1], qmi(i, mod - 2)); //预处理阶乘的逆元
}
}
void solve()
{
init();
cin >> n >> m >> k;
int ans = 0;
for (int i = n - k; i <= n; i++)
ans = (ans + mul(mul(m, C(n - 1, i - 1)), qmi(m - 1, i - 1))) % mod; //m*C(n-1,i-1) * (m-1)^(i-1)
cout << ans << endl;
}
signed main()
{
//int t;
int t = 1;
//cin >> t;
while (t--)
{
solve();
}
return 0;
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
吐槽:太菜了,题解摆这都看不懂(╯-_-)╯╧╧。本题注意点:
1. 关键的思路就是对方块根据颜色分组,然后用隔板法确定如何分组,之后对于每一组再确定染色方法。
2. 注意组合数的求法,尤其是阶乘的逆元初始化那块。