牛客挑战赛33 B-鸽天的放鸽序列

也许更好的阅读体验

\(\mathcal{Description}\)

定义一个长为\(n\)\(01\)序列\(A_1, A_2, \dots, A_n\)​的权值为\(\sum_{i=1}^n ((\sum_{j=1}^i A_j) \bmod 2)\),求有多少个长为\(n\)\(01\)序列满足有恰好\(k\)\(1\),且权值最大。
答案对\(10^9+7\)取模。

\(\mathcal{Solution}\)

显然的两个贪心

  • 最开始是\(1\)最优
  • 除最开始的\(1\)外,之后出现\(1\)两个两个出现最优

这样得到的一个序列的权值最大,其在大部分情况下是\(1\),只有\(\frac{k}{2}\)个是\(0\)
如果有偶数个\(1\),那么就放一个\(1\)在最后,这样\(0\)只会出现这一次
方案数便考虑这些\(0\)出现的位置
即在一堆\(1\)后的空格内插入\(\frac{k}{2}\)\(0\)
用组合数直接算即可

\(\mathcal{Code}\)

/*******************************
Author:Morning_Glory
LANG:C++
Created Time:2019年10月18日 星期五 19时01分41秒
*******************************/
#include <iostream>
#include <fstream>
using namespace std;
const int maxn = 1000006;
const int lim = 1000000;
const int mod = 1000000007;
int n,k,ans;
int fac[maxn],ifac[maxn],inv[maxn];
int C (int n,int m){	return 1ll*fac[n]*ifac[n-m]%mod*ifac[m]%mod;}
//{{{init
void init ()
{
	fac[0]=ifac[0]=inv[1]=1;
	for (int i=2;i<=lim;++i)	inv[i]=(-1ll*mod/i*inv[mod%i]%mod+mod)%mod;
	for (int i=1;i<=lim;++i)	fac[i]=1ll*fac[i-1]*i%mod,ifac[i]=1ll*ifac[i-1]*inv[i]%mod;
}
//}}}
int main()
{
	init();
	cin>>n>>k;
	if (!k)	return printf("1\n"),0;
	--k,--n;
	if (k&1)	--k,--n;
	printf("%d\n",C(n-k/2,k/2));
	return 0;
}

如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧

posted @ 2019-10-20 18:44  Morning_Glory  阅读(363)  评论(0编辑  收藏  举报
//