ABC156D

[题目链接]https://atcoder.jp/contests/abc156/tasks/abc156_d
简单数论问题,题意就是有n个数,不能组成a与b个数,问有多少种组合方式
那就是C(n,1)+C(n,2)+....+C(n,n)-C(n,a)-C(n,b)
和式部分为2^n-1
由于a,b的范围在2e5,直接运用逆元+原始定义求两个组合数就行了

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) ((x)&(-x))
typedef long long LL;

const LL MOD = 1e9+7;
void ex_gcd(LL a, LL b, LL& x, LL& y) {
    if(!b) {
        x = 1, y = 0;
    } else {
        ex_gcd(b, a%b, y, x);
        y -= x * (a / b);
    }
}

LL inv(LL t, LL p) {
    LL x, y, d;
    ex_gcd(t, p, x, y);
    return (x%p+p)%p;
}

LL quick_pow(LL a, LL b, LL p) {
    LL ret = 1;
    while(b) {
        if(b & 1) ret = (ret * a) % p;
        a = (a * a) % p;
        b >>= 1;
    }
    return ret;
}

void run_case() {
    LL n, a, b;
    cin >> n >> a >> b;
    if(n <= 2) {
        cout << "0";
        return;
    }
    LL all = quick_pow(2, n, MOD) - 1;
    LL fa = 1, fb = 1;
    // get a! and b!
    for(LL i = a; i >= 1; --i)
        fa = (fa * i) % MOD;
    for(LL i = b; i >= 1; --i)
        fb = (fb * i) % MOD;
    LL n1 = 1, n2 = 1;
    // get n*(n-1)---*(n-a+1)
    for(LL i = n; i >= n-a+1; --i)
        n1 = (n1 * i) % MOD;
    for(LL i = n; i >= n-b+1; --i)
        n2 = (n2 * i) % MOD;
    //get MOD inverse 
    LL invfa = inv(fa, MOD), invfb = inv(fb, MOD);
    all = ((all - n1*invfa%MOD)+MOD)%MOD;
    all = ((all - n2*invfb%MOD)+MOD)%MOD;
    cout << all;
}

int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    cout.flags(ios::fixed);cout.precision(10);
    run_case();
    cout.flush();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/GRedComeT/p/12358104.html
156