牡牛和牝牛
牡牛和牝牛
约翰要带 只牛去参加集会里的展示活动,这些牛可以是牡牛,也可以是牝牛。
牛们要站成一排,但是牡牛是好斗的,为了避免牡牛闹出乱子,约翰决定任意两只牡牛之间至少要有 只牝牛。
请计算一共有多少种排队的方法,所有牡牛可以看成是相同的,所有牝牛也一样,答案对 取模。
输入格式
一行,输入两个整数 和 。
输出格式
一个整数,表示排队的方法数。
数据范围
,
输入样例:
4 2
输出样例:
6
样例解释
种方法分别是:牝牝牝牝,牡牝牝牝,牝牡牝牝,牝牝牡牝,牝牝牝牡,牡牝牝牡。
解题思路
为了方便这里用表示牡牛,用表示牝牛。
最开始想到用动态规划,然后定义状态表示长度为且结尾有个连续的的所有合法字符串的数量,状态转移方程就是
即使对状态转移的过程进行优化,时间复杂度最好也是。
然后参考了y总的状态定义,这种定义方法是真的没想到。定义状态表示所有长度为的且以结尾的合法字符串数量。根据上一个出现的位置来划分状态,由于两个之间至少要隔个,因此上一个最近要从下标开始。状态转移方程就是,其中是指前面均是而没有的情况。
可以发现每次状态转移都是关于的一个前缀和,因此可以开个变量来记录的前缀和,这样状态转移就可以降到,因此整个算法的时间复杂度为。
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/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17082146.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
2022-02-01 dfs时间复杂度分析