鸽天的放鸽序列 组合数学+lucas

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_43880084/article/details/102650641

牛客

链接:https://ac.nowcoder.com/acm/contest/1115/B
来源:牛客网

题目描述
擅长放鸽子的鸽天要确定自己的放鸽序列。放鸽序列是一个长度为n的01序列,表示接下来n天的是否放鸽。众所周知,鸽天是很喜欢鸽的,所以它想得到放鸽天数最多的序列并计数。
放鸽序列有一个奇怪的要求,由于这个要求太奇怪了,所以接下来是一句话题意:
定义一个长为n的01序列A1,A2,…,AnA_1, A_2, \dots, A_nA1​,A2​,…,An​的权值为∑i=1n((∑j=1iAj) mod 2)\sum_{i=1}^n ((\sum_{j=1}^i A_j) \bmod 2)∑i=1n​((∑j=1i​Aj​)mod2),求有多少个长为n的01序列满足有恰好k个1,且权值最大。
答案对109+710^9+7109+7取模。
输入描述:

输入一行两个数n(1≤n≤1061 \le n \le 10^61≤n≤106)、k(0≤k≤n0 \le k \le n0≤k≤n)。

输出描述:

输出一个数,表示答案。

示例1
输入
复制

5 3

输出
复制

3

直接套了之前写的lucas的题,又不幸的发现已经忘光lucas了,看别人的码似乎不用lucasQAQ

  1. 题意很明显我们要把0放在序号为奇数的1的后面
  2. 也就转化为求有 [k/2]上取整(奇数1 的个数)个有序的盒子,每个盒子装有若干个小球(可以不装)求小球的总数为n-k的方案数
  3. ->也就是求[k/2]个非负整数加起来为n-k的方程的方案数
  4. (k+1)/2也就是奇数的1 的个数也就是我下面的-(m%2==0?m/2:m/2+1)
  5. 采用隔板法
  6. 对n件相同物品(或名额)分给m个人(或位置),允许若干个人(或位置)为空的问题,可以看成将这n件物品分成m组,允许若干组为空的问题.将n件物品分成m组,需要m-1块隔板,将这n件物品和m-1块隔板排成一排,占n+m-1位置,从这n+m-1个位置中选m-1个位置放隔板,因隔板无差别,故隔板之间无序,是组合问题,故隔板有Cn+m-1 m-1种不同的方法,再将物品放入其余位置,因物品相同无差别,故物品之间无顺序,是组合问题,只有1种放法,根据分步计数原理,共有Cn+m-1 m-1×1=Cn+m-1 m-1种排法。(百度)
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
ll pow(ll a,ll b,ll m)
{
	ll ans=1ll;
	a%=m;
	while(b)
	{
		if(b&1) ans=(ans%m)*(a%m)%m;
		b/=2;
		a=(a%m)*(a%m)%m;
	}
	ans%=m;
	return ans;
}
ll inv(ll x,ll p)
{
	return pow(x,p-2,p);
} 
ll C(ll n,ll m,ll p)
{
	if(m>n) return 0;
	ll up=1,down=1;
	for(int i=n-m+1;i<=n;i++) up=up*i%p;
	for(int i=1;i<=m;i++ ) down=down*i%p;
	return up*inv(down,p)%p; 
} 
ll lucas(ll n,ll m, ll p)
{
	if(m==0) return 1;
	return C(n%p,m%p,p)*lucas(n/p,m/p,p)%p;
}
int main()
{
	ll n,m;ll mod=1e9+7;
	while(~scanf("%lld%lld",&n,&m))
	{
		printf("%lld\n",lucas(n-m+(m%2==0?m/2:m/2+1)-1,(m%2==0?m/2:m/2+1)-1,mod)%mod);
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_43880084/article/details/102650641
今日推荐