牡牛和牝牛_牝牛是什么「建议收藏」

牡牛和牝牛_牝牛是什么「建议收藏」牡牛和牝牛 约翰要带 $N$ 只牛去参加集会里的展示活动,这些牛可以是牡牛,也可以是牝牛。 牛们要站成一排,但是牡牛是好斗的,为了避免牡牛闹出乱子,约翰决定任意两只牡牛之间至少要有 $K$ 只牝牛。 请计算一共有多少种排队的方法,所有牡牛可以看成是相同的,所有牝牛也一样,答案对 $5000011$

牡牛和牝牛_牝牛是什么「建议收藏」"

牡牛和牝牛

约翰要带 $N$ 只牛去参加集会里的展示活动,这些牛可以是牡牛,也可以是牝牛。

牛们要站成一排,但是牡牛是好斗的,为了避免牡牛闹出乱子,约翰决定任意两只牡牛之间至少要有 $K$ 只牝牛。

请计算一共有多少种排队的方法,所有牡牛可以看成是相同的,所有牝牛也一样,答案对 $5000011$ 取模。

输入格式

一行,输入两个整数 $N$ 和 $K$。

输出格式

一个整数,表示排队的方法数。

数据范围

$1 \leq N \leq {10}^{5}$,
$0 \leq K < N$

输入样例:

4 2

输出样例:

6

样例解释

$6$ 种方法分别是:牝牝牝牝,牡牝牝牝,牝牡牝牝,牝牝牡牝,牝牝牝牡,牡牝牝牡。

 

解题思路

  为了方便这里用$1$表示牡牛,用$0$表示牝牛。

  最开始想到用动态规划,然后定义状态$f(i, j)$表示长度为$i$且结尾有$j$个连续的$0$的所有合法字符串的数量,状态转移方程就是

$$f(i,j) =
\begin{cases}
\sum\limits_{u = k}^{i-1}{f(i-1, u)}, \ \ &j = 0 \\\\
f(i-1, j – 1), &j > 0
\end{cases}$$

  即使对状态转移的过程进行优化,时间复杂度最好也是$O(n^2)$。

  然后参考了y总的状态定义,这种定义方法是真的没想到。定义状态$f(i)$表示所有长度为$i$的且以$1$结尾的合法字符串数量。根据上一个$1$出现的位置来划分状态,由于两个$1$之间至少要隔$k$个$0$,因此上一个$1$最近要从下标$i – k – 1$开始。状态转移方程就是$f(i) = 1 + \sum\limits_{j = 1}^{i – k – 1}{f(j)}$,其中$+1$是指前面均是$0$而没有$1$的情况。

  可以发现每次状态转移都是关于$f(i)$的一个前缀和,因此可以开个变量来记录$f(i)$的前缀和,这样状态转移就可以降到$O(1)$,因此整个算法的时间复杂度为$O(n)$。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 1e5 + 10, mod = 5000011;
 5 
 6 int f[N];
 7 
 8 int main() {
 9     int n, m;
10     cin >> n >> m;
11     for (int i = 1, s = 0; i <= n; i++) {
12         f[i] = 1;   // 前面全是0的情况
13         if (i - m - 1 > 0) f[i] = (f[i] + s) % mod; // 至少要隔m个0
14         if (i - m > 0) s = (s + f[i - m]) % mod;    // 累加f[i]的前缀和
15     }
16     int ret = 1;
17     for (int i = 1; i <= n; i++) {  // 最后根据最后一个1出现的位置来统计答案
18         ret = (ret + f[i]) % mod;
19     }
20     cout << ret;
21     
22     return 0;
23 }
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 1e5 + 10, mod = 5000011;
 5 
 6 int f[N];
 7 
 8 int main() {
 9     int n, m;
10     cin >> n >> m;
11     for (int i = 1, s = 0; i <= n; i++) {
12         if (i - m - 1 > 0) s = (s + f[i - m - 1]) % mod;
13         f[i] = (f[i] + s + 1) % mod;
14     }
15     int ret = 1;
16     for (int i = 1; i <= n; i++) {
17         ret = (ret + f[i]) % mod;
18     }
19     cout << ret;
20     
21     return 0;
22 }

 

参考资料

  AcWing 1307. 牡牛和牝牛(算法提高课):https://www.acwing.com/video/717/

今天的文章牡牛和牝牛_牝牛是什么「建议收藏」分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/55027.html

(0)
编程小号编程小号
上一篇 2023-08-28
下一篇 2023-08-28

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注