线性 DP 计数:按前缀末位性别转移,以牝牛结尾等于总方案数,以牡牛结尾回看 K+1 位之前的总方案数,O(N) 递推取模。
OJ: roj
题目 ID: 1652
难度:普及-
标签:动态规划计数DPpython
创建: 2026-10-01 00:09
更新: 2026-10-06 01:41
题目描述
思路
设
参考代码
Python 版:
python
"""排队方案数:任意两只牡牛之间至少 K 只牝牛。O(N) DP,取模 5000011。"""
import sys
def main() -> None:
n, k = map(int, sys.stdin.read().split())
MOD = 5000011
# b[i]: 长 i 且以牡牛结尾的方案数; c[i]: 以牝牛结尾; s[i]: 总方案数
b = [0] * (n + 1)
c = [0] * (n + 1)
s = [0] * (n + 1)
s[0] = 1
for i in range(1, n + 1):
b[i] = s[i - k - 1] if i > k else 1 # 结尾放牡牛: 上一头牡牛最远到 i-k-1,否则它是第一头
c[i] = s[i - 1] # 结尾放牝牛: 任意合法前缀延长
s[i] = (b[i] + c[i]) % MOD
print(s[n] % MOD)
main()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-06 01:39
* update_at: 2026-10-06 01:39
*/
#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
const ll MOD = 5000011;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
ll n, k;
cin >> n >> k;
// s[i] 表示长度 i 的合法方案总数
vector<ll> s(n + 1);
s[0] = 1; // 空前缀
for (ll i = 1; i <= n; i++) {
ll c = s[i - 1]; // 以牝牛结尾:前 i-1 位任意合法方案
ll b;
if (i <= k) {
b = 1; // 以牡牛结尾且它是第一头牡牛
} else {
b = s[i - k - 1]; // 上一头牡牛至少在前 i-k-1 位
}
s[i] = (b + c) % MOD;
}
cout << s[n] << "\n";
return 0;
}