Luogu P6191 [USACO09FEB]Bulls And Cows S (递推)

文章目录

    • 来源:JZOJ,Luogu P6191 [传送门](https://www.luogu.com.cn/problem/P6191)
      • 题目背景
      • 题目描述
      • 解题思路
      • 美妙的Code

来源:JZOJ,Luogu P6191 传送门

题目背景

一年一度的展会要来临了, F a r m e r J o h n Farmer John FarmerJohn 想要把 N ( 1 ≤ N ≤ 100 , 0001 ≤ N ≤ 100 , 000 ) N(1 \leq N \leq 100,0001≤N≤100,000) N1N100,0001N100,000只奶牛和公牛安排在单独的一行中。 J o h n John John 发现最近公牛们非常好斗;假如两只公牛在这一行中靠的太近,他们就会吵架,以至于斗殴,破坏这和谐的环境。

题目描述

J o h n John John 非常的足智多谋,他计算出任何两只公牛之间至少要有 K ( 0 ≤ K < N 0 ≤ K < N ) K(0 \leq K \lt N0≤KK0K<N0K<N只奶牛,这样才能避免斗殴。 J o h n John John 希望你帮助他计算一下有多少种安排方法,可避免任何斗殴的的发生。 J o h n John John 认为每头公牛都是一样的,每头奶牛都是一样的。因而,只要在一些相同的位置上有不同种类的牛,那这就算两种不同的方法。

解题思路

  • 这是一道 递推,还是需要动一动脑筋的。
  • 既然是 递推,那就少不了状态和状态转移方程,其实 递推 就是 dp 的本质。首先设置状态,设当前位置放奶牛的最优解是 r [ i ] r[i] r[i] ,当前放公牛的最优解是 b [ i ] b[i] b[i],那么就可以得到状态转移方程:
    r [ i ] = r [ i − 1 ] + b [ i − 1 ] ; r[i]=r[i-1]+b[i-1]; r[i]=r[i1]+b[i1];
    b [ i ] = r [ i − k − 1 ] + r [ i − k − 1 ] ; b[i]=r[i-k-1]+r[i-k-1]; b[i]=r[ik1]+r[ik1];
    这两个状态转移方程应该还是很好理解的,第一个因为当前如果放奶牛,那么显然前一个位置可以是奶牛也可以是公牛;第二个因为当前如果放公牛,那么说明至少在 i − k − 1 i-k-1 ik1 这个位置才能放公牛,所以方法数是 r [ i − k − 1 ] + b [ i − k − 1 ] ; r[i-k-1]+b[i-k-1]; r[ik1]+b[ik1]; ,为什么加的是 r [ i − k − 1 ] r[i-k-1] r[ik1] 呢?因为举个栗子,如果加上了 r [ i − 1 ] r[i-1] r[i1],那是不是有可能吧 i − 2 i-2 i2 的位置为公牛的情况也包括进去了?而题目要求中间 k k k 头必须是奶牛,所以这样就不合法了。但是加上 r [ i − k − 1 ] r[i-k-1] r[ik1] 就没问题了,我管你第 i − k − 2 i-k-2 ik2 这个位置放的是奶牛还是公牛呢!这样一分析,能够理解了吧?

美妙的Code

#include 
using namespace std;
int r[1000000]={},b[1000000]={};
int main()
{
	int n,k;
	cin >> n >> k;
	r[1]=1;  //第1个位置放奶牛或放公牛都只有一种方案
	b[1]=1;
	for (int i=2;i<=n;i++)
	{
		r[i]=(r[i-1]+b[i-1])%5000011;  //最简单的转移房程
		if (i<=k+1) b[i]=1;  //得保证i足够大,不然数组越界QAQ
		 else b[i]=(r[i-k-1]+b[i-k-1])%5000011;  //上面解释过了
	}
	cout << (r[n]+b[n])%5000011;  //最后一个位置可以是奶牛或公牛
	return 0;
} 

你可能感兴趣的:(动态规划/递推)