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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值