AtCoder Beginner Contest 156D - Bouquet(Lacus)

Time Limit: 2 sec / Memory Limit: 1024 MB

Score : 400400 points

Problem Statement

Akari has nn kinds of flowers, one of each kind.

She is going to choose one or more of these flowers to make a bouquet.

However, she hates two numbers aa and bb, so the number of flowers in the bouquet cannot be aa or bb.

How many different bouquets are there that Akari can make?

Find the count modulo (109+7)(109+7).

Here, two bouquets are considered different when there is a flower that is used in one of the bouquets but not in the other bouquet.

Constraints

  • All values in input are integers.
  • 2≤n≤1092≤n≤109
  • 1≤a<b≤min(n,2×105)1≤a<b≤min(n,2×105)

Input

Input is given from Standard Input in the following format:

nn aa bb

Output

Print the number of bouquets that Akari can make, modulo (109+7)(109+7). (If there are no such bouquets, print 0.)


Sample Input 1 Copy

Copy

4 1 3

Sample Output 1 Copy

Copy

7

In this case, Akari can choose 22 or 44 flowers to make the bouquet.

There are 66 ways to choose 22 out of the 44 flowers, and 11 way to choose 44, so there are a total of 77 different bouquets that Akari can make.


Sample Input 2 Copy

Copy

1000000000 141421 173205

Sample Output 2 Copy

Copy

34076506

Print the count modulo (109+7)(109+7).

【题意】

Akari 有 n 种不同的花,她可以选择其中一种或多种花做成花束。但是 Akari 不喜欢花的种数恰好为 a 或 b 的花束。求出她组合花的合法方案总数,对 10^9+7 取模。

应该是c(n,1)+......c(n,n),,

因为c(n,0)+...c(n,n)=2^n;

所以推出公式:ans=(2^n)-C(n,a)-C(n,b)-1

由于n,a,b均小于模数,所以直接算组合数即可,不需要Lucas定理。

代码复杂度为:O(min(m,n-m))

适用于在m比较小,或m与n比较接近的情况。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD=1e9+7;
ll n,a,b,ans;
ll pow(ll a,ll n)
{
	ll res=1ll;
	while(n)
	{
		if (n&1)
            res=res*a%MOD;
		a=a*a%MOD;
		n>>=1;
	}
	return res%MOD;
}
ll C(ll n,ll m)
{
	if(n<m)
        return 0;
	if(n==m||!m)
	return 1;
	if(m<n-m)
	m=n-m;
	ll a=1;
	for(ll i=m+1;i<=n;++i)
	a=a*i%MOD;
	ll b=1;
	for(ll i=1;i<=n-m;++i)
	b=b*i%MOD;
	return a*pow(b,MOD-2)%MOD;
}
int main()
{
	ios::sync_with_stdio(false);
	ll n,a,b;
	cin>>n>>a>>b;
	ans=((pow(2ll,n)-C(n,a)-C(n,b)-1)%MOD+MOD)%MOD;
	cout<<ans<<endl;
    return 0;
}

用Lacus做::

需要注意的是,当同余定理用于减法的时候尽量在减完之后再加上模数,防止出现负数;

例如(6-3)% 6 = 3;

用同余定理计算后的(6%6-3%6)% 6 =(0-3)% 6 = -3;

当加上模数后 (6%6-3%6+6)% 6 =(0-3+6)% 6 = 3;

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int p=1e9+7;
ll qmi(ll a,ll k)//用到快速幂/逆元/组合公式
{
    ll res=1;
    while(k)
    {
        if(k&1)
            res=res*a%p;
        a=a*a%p;
        k>>=1;
    }
    return res;
}
ll C(int a,int b)
{
    ll res=1;
    for(ll i=1,j=a;i<=b;i++,j--)
    {
        res=res*j%p;
        res=res*qmi(i,p-2)%p;
    }
    return res;
}
ll lucas(ll a,ll b)
{
    if(a<p&&b<p)
        return C(a,b);
    return
    C(a%p,b%p)*lucas(a/p,b/p)%p;
}
int main()
{
    ios::sync_with_stdio(false);
	ll n,a,b;
	cin>>n>>a>>b;
	cout<<(qmi(2,n)-(lucas(n,a)%p+lucas(n,b)%p)%p-1+p)%p<<endl;
}

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值