容斥定理 -- 第九届ACM山东省赛F题 Four-tuples (SDUT4219)

Four-tuples

Time Limit: 2000 ms Memory Limit: 524288 KiB

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


解题报告:容斥原理
第一种特殊情况 : x1 = x2  , 第二种特殊情况 : x2 = x3  , 第三种特殊情况 : x3 = x4  , 第四种特殊情况 : x4 = x1  
总情况 sum = (r1 - l1 + 1)*(r2 - l2 + 1)*(r3 - l3 + 1)*(r4 - l4 + 1)
总特殊情况:使用容斥定理
需要注意的是 A U B U C 和 A UBUCUD 因为等号具有传递性,所以是一样的,即三交集与四交集都一样。

结果 = 总情况 - 总特殊情况

使用函数: 

mo -- 防止中间溢出(这种算法很容易爆long long)
jiao -- 分别求两个,三个,四个集合的交集

注意!这里jiao求的交集,并非容斥定理中的交集,现场时就是弄混了,然后就乱了

代码:

#include<bits/stdc++.h>

using namespace std;

long long mo(long long x)
{
	return x % ((long long)1e9 + 7);
}

long long jiao2(int l1, int r1, int l2, int r2)
{
	long long ans = min(r1, r2) - max(l1, l2) + 1;
	if(ans <= 0)
		return 0;
	else
		return ans;
}

long long jiao3(int l1, int r1, int l2, int r2, int l3,int r3)
{
	long long ans = min(r1, min(r2, r3)) - max(l1, max(l2, l3)) + 1;
	if(ans <= 0)
		return 0;
	else
		return ans;
}

long long jiao4(int l1, int r1, int l2, int r2, int l3,int r3, int l4, int r4)
{
	long long ans = min(min(r1, r2), min(r3, r4)) - max(max(l1, l2), max(l3, l4)) + 1;
	if(ans <= 0)
		return 0;
	else
		return ans;
}

int main()
{
	int l[8], r[8], t;
	long long sum;
	scanf("%d", &t);
	while(t--)
	{
		sum = 1;
		for(int i = 0; i < 4; i++)
		{
			scanf("%d%d", &l[i], &r[i]);
			l[i + 4] = l[i]; 
			r[i + 4] = r[i];
			sum *= (r[i] - l[i] + 1);
			sum %= (long long)1e9 + 7;
		}	
		// A + B + C + D  即一交集 
		for(int i = 0; i < 4; i++)
		{
			sum -= mo(mo(jiao2(l[i], r[i], l[i + 1], r[i + 1]) * (r[i + 2] - l[i + 2] + 1)) * (r[i + 3] - l[i + 3] + 1));
			while(sum < 0) sum += (long long)1e9 + 7;
		}
		// A U B 即二交集 
		for(int i = 0; i < 4; i++)
		{
			sum += jiao3(l[i], r[i], l[i + 1], r[i + 1], l[i + 2], r[i + 2]) * (r[i + 3] - l[i + 3] + 1);
			sum %= (long long)1e9 + 7;
		}
		//二交集中 A U C, B U D 
		sum += jiao2(l[0], r[0], l[1], r[1]) *  jiao2(l[2], r[2], l[3], r[3]);
		sum %= (long long)1e9 + 7;
		sum += jiao2(l[1], r[1], l[2], r[2]) *  jiao2(l[0], r[0], l[3], r[3]);
		sum %= (long long)1e9 + 7;
		// A U B U C == A U B U C U D 即三交集与四交集 
		sum -= mo(3 * jiao4(l[0], r[0], l[1], r[1], l[2], r[2], l[3], r[3]) );
		while(sum < 0) sum += (long long)1e9 + 7;
		printf("%lld\n", sum);
		//验证部分 
		sum = 0; 
		for(int i = l[0]; i <= r[0]; i++)
			for(int j = l[1]; j <= r[1]; j++)
				for(int k = l[2]; k <= r[2]; k++)
					for(int p = l[3]; p <= r[3]; p++)
					{
						if(i != j && j != k && k != p && p != i)
						{
							sum++;
							if(sum >= (1e9 + 7))
							{ 
								cout << "暴力要挂了" <<endl; 
								return 0;
								sum -= (1e9 + 7);
							} 
						}
					}
		printf("暴力标准答案:%lld\n", sum);	
	}
	return 0;
}

最后, 我国超算的发展远远超越了美帝的想象,高手在民间。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值