- 给定(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;
}