1. 程式人生 > >2018年山東省第九屆acm省賽 F題 Four-tuples(離散數學 容斥定理)

2018年山東省第九屆acm省賽 F題 Four-tuples(離散數學 容斥定理)

Four-tuples

Time Limit: 2000 ms Memory Limit: 524288 KiB

Problem Description

Given l1r1l2r2l3r3l4r4, please count the number of four-tuples (x1x2x3x4) such that lixiri and x1x2x2x3x3x4x4x1. 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

 (1T106).
For each test case, the input contains one line with 8 integers l1r1l2r2l3r3l4r4 (1liri109).

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
****************************************************/