1. 程式人生 > >容斥定理 -- 第九屆ACM山東省賽F題 Four-tuples (SDUT4219)

容斥定理 -- 第九屆ACM山東省賽F題 Four-tuples (SDUT4219)

Four-tuples

Time Limit: 2000 msMemory 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;
}

最後, 我國超算的發展遠遠超越了美帝的想象,高手在民間。