【洛谷4515】[COCI2009-2010#6] XOR(容斥)

点此看题面

  • 给定(n)个等腰直角三角形,每个三角形顶点都在边的左下方,且两条直角边与坐标轴平行。
  • 求恰好被奇数个三角形覆盖的面积总和。
  • (nle10)

等腰三角形面积交

假设我们要求出若干等腰直角三角形面积的交集。

我们首先求出最大的(x)(mx))和最大的(y)(my)),显然如果有交集,必然是一个以((mx,my))为左下方顶点的等腰直角三角形。

所以我们再枚举一遍每个三角形,求出每个三角形右下方端点在纵坐标(my)处的横坐标(x_i+r_i-(my-y_i)),它与(mx)的差值就是这个三角形只保留以((mx,my))为左下方顶点的部分时的半径。

现在要求交,那么就是要维护出最小的半径。

容斥

(n)这么小显然去枚举子集(S),求出这个子集中的三角形面积交,乘上一个容斥系数计算答案。

然而一开始(naive)了,以为容斥系数就是((-1)^{|S|-1}),但仔细一想这样求出的只是所有三角形的面积并。

不知道怎么直接猜,因此先设容斥系数为((-λ)^{|S|-1}),就是要满足:

[sum_{i=1}^nC_n^i(-λ)^{i-1}=[2 ot|n] ]

先给(sum)里面乘上一个(-λ),再配一个(i=0)的项进去,得到:

[frac{sum_{i=0}^nC_n^i(-λ)^i-1}{-λ} ]

搞这么一手当然是为了使用二项式定理,得到:

[frac{(1-λ)^n-1}{-λ} ]

考虑如果(1-λ<-1)((1-λ)^n)的绝对值大小随着(n)的增大将会爆炸,然而我们实际需要的([2 ot|n])等于(0)(1)

因此猜测(λ=2),发现代入得到:

[frac{1-(-1)^n}{2}=egin{cases}1&nin odd\0&nin evenend{cases} ]

刚好符合条件!

所以((-2)^{|S|-1})就是我们需要的容斥系数了。

代码:(O(n2^n))

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 10
#define LL long long
using namespace std;
int n,x[N+5],y[N+5],r[N+5],op[1<<N];
int main()
{
	RI i,j;for(scanf("%d",&n),i=1;i<=n;++i) scanf("%d%d%d",x+i,y+i,r+i);
	RI l=1<<n,mx,my,mr;LL s=0;for(i=1;i^l;++i)//枚举子集
	{
		for(mx=my=0,j=1;j<=n;++j) i>>j-1&1&&(mx=max(mx,x[j]),my=max(my,y[j]));//求出等腰直角三角形顶点
		for(mr=1e9,j=1;j<=n;++j) i>>j-1&1&&(mr=min(mr,x[j]+r[j]-(my-y[j])-mx));//求出最小半径
		op[i]=(i^1?op[i>>1]*(i&1?-2:1):1),mr>0&&(s+=1LL*op[i]*mr*mr);//乘上容斥系数更新答案
	}return printf("%lld.%c",s>>1,"05"[s&1]),0;
}
败得义无反顾,弱得一无是处
原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu4515.html