安吉-开营测试 T4
- 1安吉D19 T1
- 2安吉D19 T3
- 3安吉D20 模考12总结
- 4安吉D17 T3
- 5安吉D17 T4
- 6安吉D19 模考11总结
- 7安吉D15 A
- 8安吉D16 T4
- 9安吉D17 T1
- 10安吉D17 模考10总结
- 11安吉D16 T3
- 12安吉D16 模考9总结
- 13安吉D13 模考8总结
- 14安吉D13-T2
- 15安吉D13-T3
- 16安吉D12-T3
- 17安吉D11-B
- 18安吉D11-C
- 19安吉D11-D
- 20安吉D12 模考7总结
- 21安吉D12-T2
- 22安吉D11-A
- 23安吉D10 模考6总结
- 24安吉D10-T3
- 25安吉D10-T4
- 26安吉D8-E
- 27安吉D9-T4
- 28安吉D8-A
- 29安吉D8-B
- 30安吉D8-C
- 31安吉D8-D
- 32安吉D9 模考5总结
- 33安吉D9-T2
- 34安吉D9-T3
- 35安吉D6-T4
- 36安吉D4-G
- 37安吉D5-T2
- 38安吉D6 模考4总结
- 39安吉D6-T1
- 40安吉D6-T3
- 41安吉-开营测试 T4本文
- 42安吉D5 模考3总结
- 43安吉D5-T3
- 44安吉D4-A
- 45安吉D4-B
- 46安吉D4-C
- 47安吉D4:容斥原理
- 48安吉Day4-D
- 49安吉D3 模考2总结
- 50安吉D3-T1
- 51安吉D3-T2
- 52安吉D3-T4
- 53安吉D2 模考1总结
- 54安吉D2-T2
- 55安吉D1-G
- 56安吉D1-L
- 57安吉D2-T4
原题呈现
题目描述
香风智乃想画一幅画. 这幅画一共有 个像素,每个像素上可以画 种颜色的其中一种. 但是,如果某一种颜色连续重复出现太多次,那么就会显得这幅画很单调.具体来说,智乃不希望第 种颜色连续出现超过 次. 智乃想知道,她一共能画出多少种不同的画.两幅画不同,当且仅当某个像素上所画的颜色不同.
输入格式
从文件 draw.in 中读入数据. 第一行输入两个整数 . 第二行输入 个整数,第 个表示 .
输出格式
输出到文件 draw.out 中. 输出一个非负整数,表示答案对 998244353 取模后的值.
样例输入
3 31 2 3样例输出
21数据范围
对于 的数据,. 对于 的数据,. 对于 的数据,. 对于 的数据,. 对于 的数据,.
观察 的范围,显然使用 dp.
定义状态:dp[i][j] 表示考虑前 i 个像素,最后一个颜色为 j 的方案数.
一般情况下,对于一个序列,该序列的下一个像素都可以取 种颜色,但是有一个例外.由于不能连续重复出现太多次这一限制的存在,存在一种危险序列,满足以下所有条件:
- 该序列的后面 个都是颜色 .
- 该序列的第倒数 个像素的颜色不是颜色 .
此时,这个序列的下一个像素就不能是颜色 .
若定义前 个像素的合法方案数为 (无最后一个颜色的限制),合法但是后面不能再增加颜色 的方案数为 ,可以预处理出 ,通过容斥,先计算出无视这一限制后的方案数 (直接往所有合法序列后面添加颜色 ),再减去上述的不合法方案数 ,就是 dp[i][j]
故 dp[i][j] 的表达式为:
最终结果为 s[n].
这种方法的时间复杂度为 .
观察到颜色种类很多,但是限制种类很少,说明有多种颜色的限制相同.那么这些颜色就可以一起处理.
修改状态:dp[i][j] 表示考虑前 i 个像素,最后一个颜色是限制为 j 的某一种颜色的方案数.
定义 cnt[i] 表示限制为 的颜色数量.
由此,我们修改 和 的表达式:
这样的时间复杂度为 .
标程
#include <bits/stdc++.h>using namespace std;const int M = 1e5 + 100;const int N = 5005;const int MOD = 998244353;int n, m;map<int, int> cnt;int dp[N][N], s[N];int main() { cin >> n >> m; for (int i = 1; i <= m; i++) { int a; cin >> a; cnt[a]++; } vector<int> keys; for (auto i : cnt) { if (i.second != 0) keys.push_back(i.first); } s[0] = 1; for (int i = 1; i <= n; i++) { for (int j = 0; j < keys.size(); j++) { int k = keys[j]; if (i - k <= 0) { dp[i][k] = s[i - 1]; } else dp[i][k] = (0ll + s[i - 1] - (s[i - k - 1] - dp[i - k - 1][k]) + MOD) % MOD; } for (int j = 0; j < keys.size(); j++) { int k = keys[j]; (s[i] += 1ll * dp[i][k] * cnt[k] % MOD) %= MOD; } } cout << s[n];}实际上,若一个 dp 状态与之前的连续的一段状态(开头为位置 )都有关,则可能可以从状态 进行转移.
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!


