【P6191 [USACO09FEB]Bulls And Cows S】题解


题目链接

题目

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

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

思路

\(dp_i\) 表示在位置为 \(i\) 的地方放一头公牛的方案数,则我们可以枚举前一头公牛的位置:

\[dp_i=\sum_{j=0}^{i-k-1}dp_j \]

明显,可以用前缀和优化。

时间复杂度 \(O(n)\)

总结

这道题感觉上就应该是一道dp,其实也是用到了组合数学的思想。

其实这类dp只需要想到在某个点且这个点刚好为题目所给状态即可。

Code

// Problem: P6191 [USACO09FEB]Bulls And Cows S
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P6191
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define mo 5000011
#define N 100010
//#define M
int n, m, i, j, k; 
int s[N]; 

signed main()
{
//	freopen("tiaoshi.in","r",stdin);
//	freopen("tiaoshi.out","w",stdout);
	n=read(); k=read(); 
	for(i=s[0]=1; i<=n; ++i)
	{
		j=s[max(0ll, i-k-1)]; 
		s[i]=s[i-1]+j; s[i]%=mo; 
	}
	printf("%lld", s[n]); 
	return 0;
}