51nod1667(容斥)

这是一道很好的容斥原理题。
首先这里推荐两道类似的题,spojRNG(1667是它的离散版本),还有bzoj3129(两题容斥部分很类似)

我们首先把第一类区间分为(-INF,L - 1] 与 (-INF,R],把第二类区间分为[L,INF) 与 [R + 1,INF) 那么我们简单写写,把前面的值设为a - x,后面的值设为 b + y。
那么甲胜要求的就是 i(ax)>j(b+y) ,移项以后就可以发现是一堆数的和小于一个定值,这时候就要求个组合数 C(n,k) ,其中k很小,所以不用预处理再算,而是直接算(我好傻,MLE了一发)。
那么每种情况的方案数知道了,只要暴力容斥就可以了,我写了个二进制的,很慢,早知道写dfs了,还有代码也极丑,因为调调改改,也没写个函数啥的(本来以为可以写很短的,就直接在main里面写)。

代码:

//
//  main.cpp
//  1667
//
//

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int T;
int k1,k2;

const int maxn = 10;
int L1[maxn],R1[maxn],L2[maxn],R2[maxn];


typedef long long ll;
const ll mod = 1e9 + 7;



ll pow_mod(ll a,ll n){
    ll ret = 1;
    while(n > 0){
        if(n & 1) ret = ret * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return ret;
}

ll C(int n,int m){
    ll ret = 1;
    for(ll i = n;i > n - m;i--){
        ret = ret * i % mod;
    }
    //cout << 1 << endl;
    for(ll i = 1;i <= (ll) m;i++){
        ret = ret * pow_mod(i,mod - 2) % mod;
    }
    return ret;
}

int L3[maxn],L4[maxn];
int R3[maxn],R4[maxn];

int main(int argc, const char * argv[]) {
    cin >> T;
    while(T--){
        cin >> k1;
        for(int i = 1;i <= k1;i++){
            scanf("%d%d",&L1[i],&R1[i]);
            L4[i] = L1[i];
            R4[i] = R1[i];
            L1[i]--;
            R4[i]++;
        }
        cin >> k2;
        for(int i = 1;i <= k2;i++){
            scanf("%d%d",&L2[i],&R2[i]);
            L3[i] = L2[i];
            R3[i] = R2[i];
            R2[i]++;
            L3[i]--;
        }
        int n = k1 + k2;
        ll ans = 0;
        ll ans1 = 0;
        ll ans2 = 0;
        //cout << 1 << endl;
        for(int i = 0;i < (1 << n);i++){
            int sum = 0;
            int sum1 = 0;
            int num = 0;
            int num1 = 0;
            for(int j = 1;j <= k1;j++){
                if(i & (1 << (j - 1))){
                    sum += L1[j];
                    sum1 += L1[j];
                    num++;
                    num1++;
                }
                else{
                    sum1 += R1[j];
                    sum += R1[j];
                }
            }
            for(int j = k1 + 1;j <= n;j++){
                if(i & (1 << (j - 1))){
                    sum -= R2[j - k1];
                    sum1 -= R2[j - k1];
                    num++;
                    num1++;
                }else{
                    sum -= L2[j - k1];
                    sum1 -= L2[j - k1];
                }
            }
            //cout << 1 << endl;
            if(sum >= 0){
                ll tmp = C(sum + n - 1,n - 1);

                if(num & 1)ans = (ans - tmp % mod + mod) % mod;
                else ans = (ans + tmp) % mod;
            }
            //cout << 1 << endl;
            if(sum1 > 0){
                ll tmp = C(sum1 - 1 + n,n);
                if(num1 & 1) ans1 = (ans1 - tmp % mod + mod) % mod;
                else ans1 = (ans1 + tmp) % mod;
            }
            int num2 = 0;
            int sum2 = 0;
            for(int j = 1;j <= k2;j++){
                if(i & (1 << (j - 1))){
                    sum2 += L3[j];
                    num2++;
                }
                else{
                    sum2 += R3[j];
                }
            }
            for(int j = k2 + 1;j <= n;j++){
                if(i & (1 << (j - 1))){
                    sum2 -= R4[j - k2];
                    num2++;
                }else{
                    sum2 -= L4[j - k2];
                }
            }
            if(sum2 > 0){
                ll tmp = C(sum2 - 1 + n,n);
                if(num2 & 1) ans2 = (ans2 - tmp % mod + mod) % mod;
                else ans2 = (ans2 + tmp) % mod;
            }
        }

        ll all = 1;
        for(int i = 1;i <= k1;i++){
            all = all * (long long)(R1[i] - L1[i]) % mod;
        }
        for(int i = 1;i <= k2;i++){
            all = all * (long long)(R2[i] - L2[i]) % mod;
        }
        all = pow_mod(all, mod - 2);
        ans = ans * all % mod;
        ans1 = ans1 * all % mod;
        ans2 = ans2 * all % mod;
        //ll ans3 = (all - (ans + ans1) % mod + mod) % mod;
        //ans3 = ans3 * all % mod;
        cout << ans1  << " " << ans << " " << ans2 << endl;
    }
    return 0;
}

截个图纪念一下吧,第一个640分题。
第一个640分题

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值