HDU 4380 - Farmer Greedy

 

题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=4380

 

2012年第9场多校,1001 。

 

补上。

 

其实这个做法当时有想到,只是找不出 O(n^3)  范围内 求V的求法。 所以当时只好放弃~ 。。。

 

赛后才知道,有其实多校第6场,电科的1004跟这题基本上一样。。。  木有来得及去看,尴尬了。。。

 

不过电科牛给的 V的求法,其思想有点类似于单调队列,只不过队列只有一个元素。。。

 

以前没想到这种思想还可以用在几何上(做的几何题目太少,木有遇到过),各种新颖。。。

 

好吧,写写过了~~   2Y

 

写完调试过一阵,原因是while写成if 。

 

CE过一次,原因是 atan2 的参数是double,而我直接放整型进去(编译器没报错)。。。

 

PS:  后来做了 电科原题,才发现原来我代码是错的,只不过这题数据太弱了,擦,交了两次不同的错代码上去都能AC。。。

        还是电科出题严谨啊,数据、标程、描述等质量都严格把关,佩服~~~

 

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>

using namespace std;

const double pi=3.1415926;
const double eps=0e-6;

struct Point{
	int x,y;
}pq[1110];

struct Angle{
	double agl;
	int id_;
	Angle(){};
	Angle(Point a,Point b,int i){
		agl=atan2((double)b.x-a.x,(double)b.y-a.y);
		id_=i; 
	} 
}r[3000];

int pn,qn,pqn,rn;

void input(){
	int i;
	pqn=pn+qn;
	for(i=0;i<pqn;++i)
		scanf("%d%d",&pq[i].x,&pq[i].y);
}

int cmp(Angle a,Angle b){
	return a.agl<b.agl; 
}

int s[103][103];
int v[103][103],v_id[103][103];

void init_(){
	int i,j,k,cnt,mark;
	for(i=0;i<pn;++i){
		rn=0;
		for(j=0;j<pqn;j++)
			if(i!=j) r[rn++]=Angle(pq[i],pq[j],j);
		sort(r,r+rn,cmp);
		for(j=0;j<rn;j++){
			r[rn+j]=r[j];
			r[rn+j].agl+=2*pi;
		}
		cnt=0;
		mark=0;
		for(j=k=0;j<rn;j++){
			while(r[k].agl-r[j].agl<pi)
				if(r[k++].id_>=pn) cnt++;
			if(r[j].id_< pn){
				s[i][r[j].id_]=cnt;
				v[i][r[j].id_]=mark;
				v_id[i][r[j].id_]=j;
			}
			else{
				mark++,cnt--;
			}
		}
	}
}

int xmult(Point a,Point b,Point c){
	return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y); 
}

int get_v(int a,int b,int c){
	if(v_id[a][b]>v_id[a][c]) return v[a][b]-v[a][c];
	return qn+v[a][b]-v[a][c];
}

int get_sum(int a,int b,int c){
	int sum=0;
	if(xmult(pq[a],pq[b],pq[c])<0) swap(b,c);
	sum+=s[a][b]+s[b][c]+s[c][a];
	sum+=get_v(a,b,c)+get_v(b,c,a)+get_v(c,a,b);
	return sum;
}

int deal(){
	int i,j,k,res=0;
	for(i=0;i<pn;i++) 
		for(j=i+1;j<pn;j++)
			for(k=j+1;k<pn;k++)
				res+=get_sum(i,j,k)&1;
	return res;
}

int main(){
	int t=1;
	while(~scanf("%d%d",&pn,&qn)){
		input();
		init_();
		printf("Case %d: %d\n",t++,deal());
	} 
	return 0;
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值