2018年山東省第九屆acm省賽 F題 Four-tuples(離散數學 容斥定理)
阿新 • • 發佈:2018-12-24
Four-tuples
Time Limit: 2000 ms Memory Limit: 524288 KiBProblem Description
Given l1, r1, l2, r2, l3, r3, l4, r4, please count the number of four-tuples (x1, x2, x3, x4) such that li≤xi≤ri and x1≠x2, x2≠x3, x3≠x4, x4≠x1. The answer should modulo 109+7 before output.
Input
The input consists of several test cases. The first line gives the number of test cases, T (1≤T≤106).
For each test case, the input contains one line with 8 integers l1, r1, l2, r2, l3, r3, l4, r4 (1≤li≤ri≤109).
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最難受的一個題,睡覺都能感覺到F題的恐懼。
思路: 容斥定理
程式碼:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; struct node { ll l,r; }a[15],tmp; int num; ll len1,len2,len3,len4; ll len12,len23,len34,len41; ll len123,len124,len134,len234; ll len1234; ll jud(int i,int j) { if(a[i].l>a[j].r) return 0; if(a[j].l>a[i].r) return 0; ll minr,maxl; minr=min(a[i].r,a[j].r); maxl=max(a[i].l,a[j].l); tmp.l=maxl; tmp.r=minr; return minr-maxl+1; } ll jud1(int i,int j,int k) { if(jud(i,j)==0) return 0; num=4; a[++num]=tmp; return jud(num,k); } ll jud2(int i,int j,int k,int m) { num=4; if(jud(i,j)==0) return 0; a[++num]=tmp; if(jud(num,k)==0) return 0; a[++num]=tmp; return jud(num,m); } int main() { int T; scanf("%d",&T); while(T--) { for(int i=1;i<=4;i++){ scanf("%lld %lld",&a[i].l,&a[i].r); } len1=a[1].r-a[1].l+1; len2=a[2].r-a[2].l+1; len3=a[3].r-a[3].l+1; len4=a[4].r-a[4].l+1; len12=jud(1,2); len23=jud(2,3); len34=jud(3,4); len41=jud(4,1); len123=jud1(1,2,3); len124=jud1(1,2,4); len134=jud1(1,3,4); len234=jud1(2,3,4); len1234=jud2(1,2,3,4); ll sum=0; // 第一層 sum=(sum+(((((len1*len2)%mod)*len3)%mod)*len4)%mod)%mod; // 第二層 sum=(sum - (((len12*len3)%mod)*len4)%mod +mod )%mod; while(sum<0) sum+=mod; // 減去 上一層中的多加的 1==2 的情況 sum=(sum - (((len23*len1)%mod)*len4)%mod +mod )%mod; while(sum<0) sum+=mod; // 減去 上一層中的多加的 2==3 的情況 sum=(sum- (((len34*len1)%mod)*len2)%mod +mod )%mod; while(sum<0) sum+=mod; // 減去 上一層中的多加的 3==4 的情況 sum=(sum- (((len41*len2)%mod)*len3)%mod +mod )%mod; while(sum<0) sum+=mod; // 減去 上一層中的多加的 4==1 的情況 // 第三層 sum=(sum+ (len123*len4)%mod )%mod; // 加上上一層中多減的 1==2 2==3 的情況 sum=(sum+ (len12*len34)%mod )%mod; // 加上上一層中多減的 1==2 3==4 的情況 sum=(sum+ (len124*len3)%mod )%mod; // 加上上一層中多減的 1==2 2==4 的情況 sum=(sum+ (len234*len1)%mod )%mod; // 加上上一層中多減的 2==3 2==4 的情況 sum=(sum+ (len23*len41)%mod )%mod; // 加上上一層中多減的 2==3 4==1 的情況 sum=(sum+ (len134*len2)%mod )%mod; // 加上上一層中多減的 1==3 4==1 的情況 // 第四層 sum=(sum - len1234*3 +mod )%mod; // 減去上一層多加了了三次的 1==2 2==3 3==4 4==1 的情況 while(sum<0) sum+=mod; cout<<sum<<endl; } return 0; } /*************************************************** User name: yuejiutao Result: Accepted Take time: 1280ms Take Memory: 216KB Submit time: 2018-05-15 00:52:00 ****************************************************/