【容斥原理】第九届山东省赛E. Four-tuples

it2026-01-05  7

E. Four-tuples

评测平台

Description

Given 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, please count the number of four-tuples ( x 1 , x 2 , x 3 , x 4 ) (x1,x2,x3,x4) (x1,x2,x3,x4) such that l i ≤ x i ≤ r i li≤xi≤ri lixiri and x 1 ≠ x 2 , x 2 ≠ x 3 , x 3 ≠ x 4 , x 4 ≠ x 1 x1≠x2,x2≠x3,x3≠x4,x4≠x1 x1=x2,x2=x3,x3=x4,x4=x1. The answer should modulo 1 0 9 + 7 10^9+7 109+7 before output.

Input

The input consists of several test cases. The first line gives the number of test cases, T ( 1 ≤ T ≤ 1 0 6 ) T(1≤T≤10^6) T(1T106). For each test case, the input contains one line with 8 integers l 1 , r 1 , l 2 , r 2 , l 3 , r 3 , l 4 , r 4 ( 1 ≤ l i ≤ r i ≤ 1 0 9 ) l1,r1,l2,r2,l3,r3,l4,r4(1≤li≤ri≤10^9) l1,r1,l2,r2,l3,r3,l4,r4(1liri109)

Output

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

Samples Input Copy

1 1 1 2 2 3 3 4 4

Output

1

题目大意:分别给出四个区间的左右端点,然后在这四个区间中依次选择一个整数,分别用 x 1 , x 2 , x 3 , x 4 x1,x2,x3,x4 x1,x2,x3,x4 来表示,求使得所选数字满足 x 1 ≠ x 2 , x 2 ≠ x 3 , x 3 ≠ x 4 , x 4 ≠ x 1 x1≠x2,x2≠x3,x3≠x4,x4≠x1 x1=x2,x2=x3,x3=x4,x4=x1情况的共有多少组。

解题思路:利用集合容斥原理来解决,首先很容易就可以计算出全集,对于不满足上述条件的集合也可以枚举求出来,答案就是全集减去不满足条件的所有集合。下面给出图片来展现推导过程: 附上代码:

#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int mod = 1e9+7; int main() { int T; scanf("%d",&T); while(T--) { ll l1,r1,l2,r2,l3,r3,l4,r4; scanf("%lld%lld%lld%lld%lld%lld%lld%lld",&l1,&r1,&l2,&r2,&l3,&r3,&l4,&r4); ll len1 = r1 - l1 + 1; ll len2 = r2 - l2 + 1; ll len3 = r3 - l3 + 1; ll len4 = r4 - l4 + 1; ll ans = (len1 % mod) * (len2 % mod) % mod;//全集 ans = (ans % mod) * (len3 % mod) % mod; ans = (ans % mod) * (len4 % mod) % mod; ll sum1 = 0,sum2 = 0,sum3 = 0;//记录四种情况的个数 //x1==x2 ll l = max(l1,l2),r = min(r1,r2); if(r >= l) { sum1 += ((((r - l + 1) % mod) * (len3 % mod) % mod) % mod) * (len4 % mod) % mod; } //x1==x4 l = max(l1,l4),r = min(r1,r4); if(r >= l) { sum1 += ((((r - l + 1) % mod) * (len2 % mod) % mod) % mod) * (len3 % mod) % mod; } //x2==x3 l = max(l2,l3),r = min(r2,r3); if(r >= l) { sum1 += ((((r - l + 1) % mod) * (len1 % mod) % mod) % mod) * (len4 % mod) % mod; } //x3==x4 l = max(l3,l4),r = min(r3,r4); if(r >= l) { sum1 += ((((r - l + 1) % mod) * (len1 % mod) % mod) % mod) * (len2 % mod) % mod; } //x1==x2==x4 l = max(l1,max(l2,l4)),r=min(r1,min(r2,r4)); if(r >= l) { sum2 += ((r - l + 1) % mod) * (len3 % mod) % mod; } //x1==x2==x3 l = max(l1,max(l2,l3)),r=min(r1,min(r2,r3)); if(r >= l) { sum2 += ((r - l + 1) % mod) * (len4 % mod) % mod; } //x1==x3==x4 l = max(l1,max(l3,l4)),r=min(r1,min(r3,r4)); if(r >= l) { sum2 += ((r - l + 1) % mod) * (len2 % mod) % mod; } //x2==x3==x4 l = max(l2,max(l3,l4)),r=min(r2,min(r3,r4)); if(r >= l) { sum2 += ((r - l + 1) % mod) * (len1 % mod) % mod; } //x1==x2&&x3==x4 ll L1 = max(l1,l2),R1 = min(r1,r2),L2 = max(l3,l4),R2 = min(r3,r4); if(R1 >= L1 && R2 >= L2) { sum2 += ((R1 - L1 + 1) % mod) * ((R2 - L2 + 1) % mod) % mod; } //x1==x4&&x2==x3 L1 = max(l1,l4),R1 = min(r1,r4),L2 = max(l2,l3),R2 = min(r2,r3); if(R1 >= L1 && R2 >= L2) { sum2 += ((R1 - L1 + 1) % mod) * ((R2 - L2 + 1) % mod) % mod; } //x1==x2==x3==x4 l = max(l1,max(l2,max(l3,l4))),r = min(r1,min(r2,min(r3,r4))); if(r >= l) { sum3 += r - l + 1; } ans -= sum1; ans = ((ans % mod) + mod) % mod; ans += sum2; ans %= mod; ans -= 3 * sum3; ans = ((ans % mod) + mod) % mod; printf("%lld\n",ans); } return 0; } /* 1 1 1000000000 1 1000000000 1 1000000000 1 1000000000 */

注意:取余的时候需要特别注意一下,稍有不慎就很容易溢出。 再者就是当考虑,( x 1 x1 x1== x 2 x2 x2 && x 3 x3 x3== x 4 x4 x4)和( x 1 x1 x1== x 3 x3 x3 && x 2 x2 x2== x 4 x4 x4)的时候。拿出其中一个来进行解释,如果&&的左右两边都有交集存在的话,只需计算两个交集中元素的数量相乘即可,如果有一方不存在交集,此种情况的结果直接为 0 0 0 就行。

最新回复(0)