容斥定理 -- 第九届ACM山东省赛F题 Four-tuples

Four-tuples

 

 

 

Time Limit: 2000 msMemory Limit: 524288 KiB

Output

For each test case, output one line containing one integer, representing the answer.

Sample Input

1
1 1 2 2 3 3 4 4

Sample Output

1

Hint

Source

2018 Shandong ACM programing real contest, on-site problem replay

 

 

容斥原理!本来领导说省赛完之后要考离散的,结果还是没有复习离散书。。结果就GG了。。。

其实大概原理知道,但是没怎么用过,结果比赛时一紧张,就很emmm。。。

容斥原理最常见的一个就是用补集减。。结果当时比赛的时候想到是容斥原理了,

但是用的不是补集减做的,我是直接想用容斥,然后推了半天,没推出来,最后的一发,直接4区间乘积也没过,

很奇怪为什么我们的没有过。。不是说好的随便交就过吗qwq。。。

 

题解思路源自转载               链接          o#(这里、这里)#o

 

 

第一种特殊情况 : x1 = x2  , 第二种特殊情况 : x2 = x3  , 第三种特殊情况 : x3 = x4  , 第四种特殊情况 : x4 = x1  

总情况 sum = (r1 - l1 + 1)*(r2 - l2 + 1)*(r3 - l3 + 1)*(r4 - l4 + 1)

总特殊情况:使用容斥定理

需要注意的是 A U B U C 和 A UBUCUD 因为等号具有传递性,所以是一样的,即三交集与四交集都一样。

结果 = 总情况 - 总特殊情况

 

 

理解代码的时候注意交集和容斥的交集有区分,

 

也就是  答案=sum-(A∪BCD)

 

(A∪BCD)=A+B+C+D│

                                -│A∩B│-│A∩C│-│A∩D│-│B∩C│-│B∩D│-│C∩D

                               +│A∩B∩C│+│A∩B∩D│+│A∩C∩D+│B∩C∩D

                                -│A∩B∩C∩D│(容斥原理

 

假设A为第一种情况,B为第二种。。。。。

 

那么(易错点,这里容易弄混)A=(len(AB))*(r3 - l3 + 1)*(r4 - l4 + 1),B=。。。。

 

下面继续按惯例,贴别人的代码,

 

代码(别人的!有空自己会敲一遍)

 

#include<bits/stdc++.h>

using namespace std;

long long mo(long long x)
{
    return x % ((long long)1e9 + 7);
}

long long jiao2(int l1, int r1, int l2, int r2)
{
    long long ans = min(r1, r2) - max(l1, l2) + 1;
    if(ans <= 0)
        return 0;
    else
        return ans;
}

long long jiao3(int l1, int r1, int l2, int r2, int l3,int r3)
{
    long long ans = min(r1, min(r2, r3)) - max(l1, max(l2, l3)) + 1;
    if(ans <= 0)
        return 0;
    else
        return ans;
}

long long jiao4(int l1, int r1, int l2, int r2, int l3,int r3, int l4, int r4)
{
    long long ans = min(min(r1, r2), min(r3, r4)) - max(max(l1, l2), max(l3, l4)) + 1;
    if(ans <= 0)
        return 0;
    else
        return ans;
}

int main()
{
    int l[8], r[8], t;
    long long sum;
    scanf("%d", &t);
    while(t--)
    {
        sum = 1;
        for(int i = 0; i < 4; i++)
        {h7
            scanf("%d%d", &l[i], &r[i]);
            l[i + 4] = l[i];
            r[i + 4] = r[i];
            sum *= (r[i] - l[i] + 1);
            sum %= (long long)1e9 + 7;
        }
        // A + B + C + D  即一交集
        for(int i = 0; i < 4; i++)
        {
            sum -= mo(mo(jiao2(l[i], r[i], l[i + 1], r[i + 1]) * (r[i + 2] - l[i + 2] + 1)) * (r[i + 3] - l[i + 3] + 1));
            while(sum < 0) sum += (long long)1e9 + 7;
        }
        // A U B 即二交集
        for(int i = 0; i < 4; i++)
        {
            sum += jiao3(l[i], r[i], l[i + 1], r[i + 1], l[i + 2], r[i + 2]) * (r[i + 3] - l[i + 3] + 1);
            sum %= (long long)1e9 + 7;
        }
        //二交集中 A U C, B U D
        sum += jiao2(l[0], r[0], l[1], r[1]) *  jiao2(l[2], r[2], l[3], r[3]);
        sum %= (long long)1e9 + 7;
        sum += jiao2(l[1], r[1], l[2], r[2]) *  jiao2(l[0], r[0], l[3], r[3]);
        sum %= (long long)1e9 + 7;
        // A U B U C == A U B U C U D 即三交集与四交集
        sum -= mo(3 * jiao4(l[0], r[0], l[1], r[1], l[2], r[2], l[3], r[3]) );
        while(sum < 0) sum += (long long)1e9 + 7;
        printf("%lld\n", sum);
    }
    return 0;
}

 

自己敲了一遍

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const long long mod = 1e9+7;

ll Mod(ll t){return t%mod;}

ll jiao2(ll l1,ll r1,ll l2,ll r2)
{
    ll ans=min(r1,r2)-max(l1,l2)+1;
    return ans>0?ans:0;
}

ll jiao3(ll l1,ll r1,ll l2,ll r2,ll l3,ll r3)
{
    ll ans=min(r1,min(r2,r3))-max(l1,max(l2,l3))+1;
    return ans>0?ans:0;
}

ll jiao4(ll l1,ll r1,ll l2,ll r2,ll l3,ll r3,ll l4,ll r4)
{
    ll ans=min(min(r1,r2),min(r3,r4))-max(max(l1,l2),max(l3,l4))+1;
    return ans>0?ans:0;
}


int main()
{
    ll l[10],r[10];
    int t;
    scanf("%d",&t);

    while(t--)
    {
        ll ans=1;
        for(int i=0;i<4;i++)
        {
            scanf("%lld %lld",&l[i],&r[i]);
            l[i+4]=l[i];
            r[i+4]=r[i];
            ans*=(r[i]-l[i]+1);
            ans%=mod;
        }

        for(int i=0;i<4;i++)
        {
            ans-=Mod( Mod( jiao2(l[i],r[i],l[i+1],r[i+1])*(r[i+2]-l[i+2]+1) )*(r[i+3]-l[i+3]+1));
            while(ans<0)ans+=mod;
        }

        for(int i=0;i<4;i++)
        {
            ans+=Mod(jiao3(l[i],r[i],l[i+1],r[i+1],l[i+2],r[i+2])*(r[i+3]-l[i+3]+1));
            ans%=mod;
        }

        ans+=Mod(jiao2(l[0],r[0],l[1],r[1])*jiao2(l[2],r[2],l[3],r[3]));
        ans%=mod;
        ans+=Mod(jiao2(l[0],r[0],l[3],r[3])*jiao2(l[1],r[1],l[2],r[2]));
        ans%=mod;

        ans-=(3*Mod(jiao4(l[0],r[0],l[1],r[1],l[2],r[2],l[3],r[3])));

        while(ans<0)ans+=mod;

        printf("%lld\n",ans);
    }

    return 0;
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值