P4515 [COCI2009-2010#6] XOR

[COCI2009-2010#6] XOR

题目描述

坐标系下有若干个等腰直角三角形,且每个等腰直角三角形的直角顶点都在左下方,两腰与坐标轴平行。被奇数个三角形覆盖的面积部分为灰色,被偶数个三角形覆盖的面积部分为白色,如下图所示。

已知 \(N\)个等腰直角三角形的顶点坐标及腰长,求灰色部分面积。

\(1 \leq N \leq 10, 1 \leq X, Y, R \leq 10^6\)

思路点拨

容斥做法

这题的数据范围十分的明显, \(n=10\) ,搜索,状压,容斥什么的。再加上本题的题目配图,很容易往容斥的角度思考问题。本题具体有两种容斥做法:

第一种(不好想但是简单)

我们假设一片区域被 \(m\) 个三角形包含,这 \(m\) 个三角形共同组成了一个集合 \(S\)
有一个结论:

\[[2 \nmid m]=\sum_{T \subseteq S}(-1)^{|T|+1}2^{|T|-1} \]

这里给出一个简单的证明:

\[\sum_{T \subseteq S}(-1)^{|T|+1}2^{|T|-1} = \sum_{i=1}^{|S|}C_{m}^{i} (-1)^{i+1}2^{i-1} \]

\((-1)^{i+1}=(-1)^{i-1}\) 本质上是一样的,方便与后面的 \(2^{i-1}\) 同类项。

\[=\sum_{i=1}^{m}C_{m}^{i} (-1)^{i-1}2^{i-1}=\sum_{i=1}^m C_{m}^i (-2)^{i-1} \]

这个东东有点像 \((-2+1)^m\) 的二项式定理展开式,我们将 \((-2)^{i-1}\) 凑成 \((-2)^{i}\) , 然后二项式定理减去 \(i=0\) 的贡献就可以了。

\[=\dfrac{-1}{2}\sum_{i=1}^m C_{m}^i (-2)^{i}=\dfrac{\sum_{i=0}^m C_{m}^i (-2)^{i}-1}{-2} \]

\[=\dfrac{1-(-2+1)^{m}}{2} = [2 \nmid m] \]

OK,我们就获得了一个容斥系数。代码实现比较简单。

第二种(好想,二项式反演)

我们令 \(f(m)\) 表示 \(m\) 的容斥系数, \(g(m)=[2 \nmid m]\)

那么应该有 $$g(m)=\sum_{i=1}^m C_{m}^i f(i)$$

二项式反演得:

\[f(m)=\sum_{i=0}^m (-1)^{m-i} C_{m}^i g(i) \]

其实以上两种方法得到的容斥系数是一样的,至于为什么是一样的,留给读者自己思考。可以从杨辉三角或者组合恒等式的角度进行思考。

以上的两种做法都需要使用多个三角形求交,初中数学自己推一下,这里给出代码:

\(code\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-f;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+ch-'0';
		ch=getchar();
	}
	return x*f;
}
const int MAXN=11;
int n;
struct node{
	int x,y,w;
}a[MAXN];
int siz(node A){
	return A.w*A.w;
}
node insert(node A,node B){
	node C;
	C.x=max(A.x,B.x);
	C.y=max(A.y,B.y);
	C.w=max((int)0,min(A.x+A.y+A.w,B.x+B.y+B.w)-C.x-C.y);
	return C;
}
signed main(){
	n=read();
	for(int i=1;i<=n;i++){
		a[i].x=read(),a[i].y=read();
		a[i].w=read();
	}
	int ans=0; 
	for(int i=1;i<(1<<n);i++){
		node temp;
		int flag=0,popcount=0;
		for(int j=0;j<n;j++){
			if(!(i&(1<<j))) continue;
			popcount++;
			if(!flag){
				temp=a[j+1];
				flag=1;
			} 
			else temp=insert(temp,a[j+1]);
		}
		if(popcount&1) ans+=(siz(temp)<<popcount);
		else ans-=(siz(temp)<<popcount);
	}
	printf("%.1lf",1.0*ans/4);
	return 0;
}
posted @ 2023-06-07 07:58  Diavolo-Kuang  阅读(124)  评论(0编辑  收藏  举报