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

也许更好的阅读体验

(mathcal{Description})

定义一个长为(n)(01)序列(A_1, A_2, dots, A_n)​的权值为(sum_{i=1}^n ((sum_{j=1}^i A_j) mod 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
"),0;
	--k,--n;
	if (k&1)	--k,--n;
	printf("%d
",C(n-k/2,k/2));
	return 0;
}

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

原文地址:https://www.cnblogs.com/Morning-Glory/p/11708523.html