CF1475 E. Advertising Agency

题目的镜像网站链接

题目大意
给你n个数,选出其中的k个数,使这k个数的和最大,求总共有多少种选法,满足题目的要求。

思路
先对这n个数进行从大到小的排序,找到前k大的n个数,为了保证和是最大的,只能改变k个数中最小的数MINNUM的选择情况,因为比MINNUM 大的数会被全部选中,即会出现 C n n = 1 , C_{n}^{n}= 1, Cnn=1的情况,因此只有最后一个数与和它等值的数在k个数中与n个数中的分布情况,会决定最后的答案。

假设在k个数中,共有M个值为MINNUM,在n个数中,有N个值为MINNUM,即可得
数学公式 C N M C_{N}^{M} CNM
该值也就是最后的答案。

重要方法
为了在n较大的情况下(n<=1000)下算得 C N M C_{N}^{M} CNM需要使用快速计算组合数的模板
该模板如下

const int MOD = 1e9+7;

ll  fac[N];//储存除模后的阶乘的值

ll Mode(ll a, ll b, ll mode)//快速幂
{
	ll sum = 1;
	a = a % mode;
 	while (b > 0)
	{	
	 	if (b % 2 == 1)		//判断是否是奇数,是奇数的话将多出来的数事先乘如sum			
		{ 
			sum = (sum * a) % mode; 
		}		
		b /= 2;		
		a = (a * a) % mode;
		// 不断的两两合并再取模,减小a和b的规模	
	}	
	return sum%mode;
}

ll C(ll m,ll n)//快速计算组合数
{
	return fac[n]*Mode(fac[m]*fac[n-m]%MOD,MOD-2,MOD)%MOD;
}

完整代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>

#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long

using namespace std;

bool cmp(ll a,ll b)
{
	return a > b;
}

const int N = 1e3+5;

const int MOD = 1e9+7;

ll a[N], fac[N];

ll Mode(ll a, ll b, ll mode)
{
	ll sum = 1;

	a = a % mode;
	
 	while (b > 0)
	{	
	 	if (b % 2 == 1)		//判断是否是奇数,是奇数的话将多出来的数事先乘如sum			
		{ 
			sum = (sum * a) % mode; 
		}
				
		b /= 2;		
		
		a = (a * a) % mode;
		// 不断的两两合并再取模,减小a和b的规模	
	}	
	
	return sum%mode;
}

ll C(ll m,ll n)
{
	return fac[n]*Mode(fac[m]*fac[n-m]%MOD,MOD-2,MOD)%MOD;
}

int main()
{
	int t;
	
	scanf("%d",&t);
	
	fac[0] = 1;
	
	for(int i=1;i<=1000;++i)//初始化阶乘的值
	{
		fac[i] = fac[i-1]*i%MOD;
	}
	
	while(t--)
	{
		int n, k;
		
		scanf("%d %d",&n,&k);
		
		for(int i=1;i<=n;++i)
		{
			scanf("%lld",&a[i]);
		}
		
		sort(a+1,a+n+1,cmp);
		
		int x = 1, y = 0;
		
		for(int i=k-1;i>=1;--i)
		{
			if(a[k]==a[i])
			{
				++x;
			}
			else
			{
				break;
			}
		}
		
		for(int i=k+1;i<=n;++i)
		{
			if(a[k]==a[i])
			{
				++y;
			}
			else
			{
				break;
			}
		}
		
		ll M = x, N = x + y;
		
		printf("%lld\n",C(M,N));
	}
	
	return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值