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
容斥原理!本来领导说省赛完之后要考离散的,结果还是没有复习离散书。。结果就GG了。。。
其实大概原理知道,但是没怎么用过,结果比赛时一紧张,就很emmm。。。
容斥原理最常见的一个就是用补集减。。结果当时比赛的时候想到是容斥原理了,
但是用的不是补集减做的,我是直接想用容斥,然后推了半天,没推出来,最后的一发,直接4区间乘积也没过,
很奇怪为什么我们的没有过。。不是说好的随便交就过吗qwq。。。
题解思路源自转载 链接 o#(这里、这里)#o
第一种特殊情况 : 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 因为等号具有传递性,所以是一样的,即三交集与四交集都一样。
结果 = 总情况 - 总特殊情况
理解代码的时候注意交集和容斥的交集有区分,
也就是 答案=sum-(A∪B∪C∪D)
而(A∪B∪C∪D)=│A│+│B│+│C│+│D│
-│A∩B│-│A∩C│-│A∩D│-│B∩C│-│B∩D│-│C∩D│
+│A∩B∩C│+│A∩B∩D│+│A∩C∩D│+│B∩C∩D│
-│A∩B∩C∩D│(容斥原理)
假设A为第一种情况,B为第二种。。。。。
那么(易错点,这里容易弄混)A=(len(A∩B))*(r3 - l3 + 1)*(r4 - l4 + 1),B=。。。。
下面继续按惯例,贴别人的代码,
代码(别人的!有空自己会敲一遍)
#include
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++)
{h7
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);
}
return 0;
}
自己敲了一遍
#include
using namespace std;
typedef long long ll;
const long long mod = 1e9+7;
ll Mod(ll t){return t%mod;}
ll jiao2(ll l1,ll r1,ll l2,ll r2)
{
ll ans=min(r1,r2)-max(l1,l2)+1;
return ans>0?ans:0;
}
ll jiao3(ll l1,ll r1,ll l2,ll r2,ll l3,ll r3)
{
ll ans=min(r1,min(r2,r3))-max(l1,max(l2,l3))+1;
return ans>0?ans:0;
}
ll jiao4(ll l1,ll r1,ll l2,ll r2,ll l3,ll r3,ll l4,ll r4)
{
ll ans=min(min(r1,r2),min(r3,r4))-max(max(l1,l2),max(l3,l4))+1;
return ans>0?ans:0;
}
int main()
{
ll l[10],r[10];
int t;
scanf("%d",&t);
while(t--)
{
ll ans=1;
for(int i=0;i<4;i++)
{
scanf("%lld %lld",&l[i],&r[i]);
l[i+4]=l[i];
r[i+4]=r[i];
ans*=(r[i]-l[i]+1);
ans%=mod;
}
for(int i=0;i<4;i++)
{
ans-=Mod( Mod( 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(ans<0)ans+=mod;
}
for(int i=0;i<4;i++)
{
ans+=Mod(jiao3(l[i],r[i],l[i+1],r[i+1],l[i+2],r[i+2])*(r[i+3]-l[i+3]+1));
ans%=mod;
}
ans+=Mod(jiao2(l[0],r[0],l[1],r[1])*jiao2(l[2],r[2],l[3],r[3]));
ans%=mod;
ans+=Mod(jiao2(l[0],r[0],l[3],r[3])*jiao2(l[1],r[1],l[2],r[2]));
ans%=mod;
ans-=(3*Mod(jiao4(l[0],r[0],l[1],r[1],l[2],r[2],l[3],r[3])));
while(ans<0)ans+=mod;
printf("%lld\n",ans);
}
return 0;
}