yts1999 T2 容斥原理

14 篇文章 0 订阅
1 篇文章 0 订阅

题意:给定 l 1 , r 1 , l 2 , r 2 , l 3 , r 3 , l 4 , r 4 l1, r1, l2, r2, l3, r3, l4, r4 l1,r1,l2,r2,l3,r3,l4,r4,试求满足 l i ≤ x i ≤ r i l_i ≤ x_i ≤ r_i lixiri x 1 ≠ x 2 , x 2 ≠ x 3 , x 3 ≠ x 4 , x 4 ≠ x 1 x1 \ne x2, x2 \ne x3, x3 \ne x4, x4 \ne x1 x1̸=x2,x2̸=x3,x3̸=x4,x4̸=x1
的四元组 ( x 1 , x 2 , x 3 , x 4 ) (x1, x2, x3, x4) (x1,x2,x3,x4) 的数量对 1 0 9 + 7 10^9 + 7 109+7 取模的结果。

很容易看出是容斥原理,可是该怎么容斥呢?考场上没想出来,我还是太弱了。

定义 s u m i = r i − l i + 1 sum_i=r_i-l_i+1 sumi=rili+1,即为每个区间的长度。首先,对于没有限制的情况,根据乘法原理,显然有 a n s = ∏ i = 1 4 s u m i ans=\prod_{i=1}^4sum_i ans=i=14sumi种四元组。

容斥原理奇加偶减,即若为奇数个数相同的就让 a n s ans ans加,否则减。

比如像 1123 1123 1123这样有两个相同的情况,因为是偶数个数相同,所以要让ans减,我们找第一个区间和第二个区间的交集, a n s ans ans就应该减去这个交集的长度 ∗ s u m 3 和 s u m 4 *sum_3和sum_4 sum3sum4。同样对于第二第三个区间的交,第三第四个区间的交,第四第一个区间的交也做同样的操作,对于其他的也如此。

我们发现有特殊情况,像 1122 , 1221 1122,1221 11221221这样两种情况,在之前的一步被减去了两次,对于类似 1122 1122 1122的这种情况,我们要让 a n s ans ans加上第一第二个区间交的长度 ∗ * 第三第四个区间交的长度。特殊情况特殊考虑,所以即使相同的数为偶数,也是要让 a n s ans ans加。对于类似 1221 1221 1221的这种情况也类似。

对于 1111 1111 1111这样的情况,我们发现它在特殊情况中被加了2次,所以应该减去三倍的区间交的长度。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=1e9+7;
ll l[5],r[5];
ll T,sum[5];
int main()
{
    cin>>T;
    while(T--)
    {
        for(int i=1;i<=4;++i)
            scanf("%lld%lld",&l[i],&r[i]);
        for(int i=1;i<=4;++i)
            sum[i]=r[i]-l[i]+1;
        ll ans=(sum[1]%mod*sum[2]%mod*sum[3]%mod*sum[4]%mod)%mod;
        
        ll L=max(l[1],l[2]);//例如1123 
        ll R=min(r[1],r[2]);
        if(R-L>=0)
            ans=(ans%mod-(R-L+1)*sum[3]%mod*sum[4]%mod+mod)%mod;
            
        L=max(l[2],l[3]);
        R=min(r[2],r[3]);
        if(R-L>=0)
            ans=(ans%mod-(R-L+1)*sum[1]%mod*sum[4]%mod+mod)%mod;
            
        L=max(l[3],l[4]);
        R=min(r[3],r[4]);
        if(R-L>=0)
            ans=(ans%mod-(R-L+1)*sum[1]%mod*sum[2]%mod+mod)%mod;
            
        L=max(l[4],l[1]);
        R=min(r[4],r[1]);
        if(R-L>=0)
            ans=(ans%mod-(R-L+1)*sum[2]%mod*sum[3]%mod+mod)%mod;
            
        ll L1=max(l[1],l[2]);//例如1122 
        ll R1=min(r[1],r[2]);
        ll L2=max(l[3],l[4]);
        ll R2=min(r[3],r[4]);
        if((R1-L1>=0)&&(R2-L2>=0))
            ans=(ans%mod+(R1-L1+1)%mod*(R2-L2+1)%mod+mod)%mod;
        
        L1=max(l[2],l[3]);
        R1=min(r[2],r[3]);
        L2=max(l[1],l[4]);
        R2=min(r[1],r[4]);
        if((R1-L1>=0)&&(R2-L2>=0))
            ans=(ans%mod+(R1-L1+1)%mod*(R2-L2+1)%mod+mod)%mod;				
        
        L=max(max(l[1],l[2]),l[3]);//例如1112 
        R=min(min(r[1],r[2]),r[3]);
        if(R-L>=0)
            ans=(ans%mod+(R-L+1)*sum[4]%mod+mod)%mod;
            
        L=max(max(l[2],l[3]),l[4]);
        R=min(min(r[2],r[3]),r[4]);
        if(R-L>=0)
            ans=(ans%mod+(R-L+1)*sum[1]%mod+mod)%mod;
            
        L=max(max(l[3],l[4]),l[1]);
        R=min(min(r[3],r[4]),r[1]);
        if(R-L>=0)
            ans=(ans%mod+(R-L+1)*sum[2]%mod+mod)%mod;
            
        L=max(max(l[4],l[1]),l[2]);
        R=min(min(r[4],r[1]),r[2]);
        if(R-L>=0)
            ans=(ans%mod+(R-L+1)*sum[3]%mod+mod)%mod;
            
        L=max(max(l[1],l[2]),max(l[3],l[4]));//例如1111 
        R=min(min(r[1],r[2]),min(r[3],r[4]));
        if(R-L>=0)
            ans=(ans%mod-3*(R-L+1)%mod+mod)%mod;
        printf("%lld\n",(ans+mod)%mod);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值