题目-牡牛和牝牛(组合计数)

问题分析
大意就是一共 n n n只牛, 牛分为 1 1 1型牛, 和 0 0 0型牛, 要求在每两个 1 1 1之间至少有 k k k个 0 0 0型牛, 问方案数
d p dp dp方式解决组合计数问题, 定义状态表示 f ( i ) f(i) f(i)考虑前 i i i头牛, 并且 i i i位置是 1 1 1型牛的方案数量
f ( i ) = f ( i − k − 1 ) + f ( i − k − 2 ) + . . . + f ( 0 ) f(i) = f(i - k - 1) + f(i - k - 2) + ... + f(0) f(i)=f(i−k−1)+f(i−k−2)+...+f(0)
边界情况, 当 f ( 0 ) f(0) f(0)相当于没有 1 1 1型牛只有 0 0 0型牛的情况, 也就是说 f ( 0 ) = 1 f(0) = 1 f(0)=1
如果直接计算, 状态数量是 O ( n ) O(n) O(n), 算法时间复杂度是 O ( n 2 ) O(n ^ 2) O(n2), 需要进行优化
因为每次计算都是区间和, 可以使用前缀和优化
算法步骤
- 初始化 f ( 0 ) f(0) f(0)
- 假设前缀和函数是 s s s, f ( i ) = s i − k − 1 f(i) = s_{i - k - 1} f(i)=si−k−1
- 对前缀和进行累加, s i = s i − 1 + f ( i ) s_i = s_{i - 1} +f(i) si=si−1+f(i)
- 对答案进行化整为零的过程, 假设答案的集合是 S S S, 可以按照最后一个 1 1 1的位置对集合进行划分, 也就是说 a n s = f ( 0 ) + f ( 1 ) + . . . + f ( n ) = s n ans = f(0) + f(1) + ... + f(n) = s_n ans=f(0)+f(1)+...+f(n)=sn, 因此答案就是 s n s_n sn
优化后的时间复杂度是 O ( n ) O(n) O(n)
代码实现
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, MOD = 5000011;
int n, k;
int f[N], s[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> k;
f[0] = 1;
s[0] = 1;
for (int i = 1; i <= n; ++i) {
f[i] = s[max(i - k - 1, 0)];
s[i] = (s[i - 1] + f[i]) % MOD;
}
cout << s[n] << '\n';
return 0;
}

京公网安备 11010502036488号