【hnoi2007】

本文回顾了hnoi2007年的比赛,指出day1难度高于day2。介绍了四道题目,包括海盗分宝(求解最优策略)、最小矩形覆盖(使用凸包和动态维护求解)、胜负一子(五子棋残局的必胜策略)和分裂游戏(博弈论问题,通过状态拆分解决)。文章探讨了每道题目的解题思路和难点,并提供了部分解决方案。
摘要由CSDN通过智能技术生成


      盾哥说hnoi年份靠前的题目价值不大,所以考虑07年选做一些题后转战poi吧。


      hnoi2007简直是奇葩的一年,day1明显难于day2(day1就算算上的第四题(那个时候还没有cdq的论文),也只有两道可做题,而day2有三道可做题)

     

       day1

      海盗分宝:

      。。。。。。

      求神牛解释题意。。。。。。

      bzoj 0 Submit  0 AC


      最小矩形覆盖:

     题意: 用面积最小的矩形覆盖给定的点,点数:50000

       很显然的是,必定有两点同时在一条边上时,面积才会最小,可以想象,如果每条边只有1个点在上面,我们可以把这个矩形缩小,而矩形可以通过旋转保证覆盖所有点,

      直到有两个点在一条边上从而限制了矩形的旋转。

      有了这个猜想,我们可以写出一个利用4条直线进行卡壳的方法,先做遍凸包, 在凸包上卡出最左点,最右点,最高点,最低点,动态维护,更新面积。

      //用向量表示直线,第一个点精度被卡>.<太凄惨了=。=!55~~~~~~~ 反正是写的无比丑陋。


  

# include <cstdlib>
# include <cstdio>
# include <cmath>
# include <cstring>

using namespace std;

const int N = 60000;
const double eps = 1e-9;
struct point {double x, y, z;}pans[5], zd[5], vec[5], peak[5], line[N],d[N], edge[N], pt[N];
int nex[N], que[N], top, n;
int g[N];
double ans=1e100, Cos[N], Sin[N];

bool bezero(double x) {return x<eps&&x>-eps?true:false;};
double max(double x, double y) {return x>y?x:y;};

int cmp(const void *i, const void *j)
{
	point p = *(point *)i, q = *(point *)j;
	if (p.y<q.y-eps||(bezero(p.y-q.y)&& p.x<q.x-eps)) return -1;
	else return 1;
}
double dot(point u, point v)
{
	return u.x*v.x+u.y*v.y;
}
double cross2(point u, point v, point w)
{
	double x1 = v.x-u.x,y1 = v.y-u.y, x2=w.x-u.x, y2=w.y-u.y;
	return x1*y2 - x2*y1;
}
double sqr(double x) {return x*x;};
void simple(point &u)
{
	double len = sqrt(sqr(u.x)+sqr(u.y));
	u.x/=len; u.y/=len;
}
double dist(point u, point v)
{
	return (sqrt(sqr(u.x-v.x)+sqr(u.y-v.y)));
}
void prepare()
{
	int i;
	qsort(d+1, n, sizeof(d[1]), cmp);
	que[1] = 1; top = 1;
	for (i = 2; i <= n; i++)
	{
		for (;top > 1&&cross2(d[que[top-1]], d[que[top]], d[i])<=0;top--);
		que[++top] = i;
	}
	for (i = n-1; i >= 2; i--)
	{
		for (;top > 1&&cross2(d[que[top-1]], d[que[top]], d[i])<=0;top--);
		que[++top] = i;
	}
	for (i = 1; i <= top; i++)
	  pt[top-i+1] = d[que[i]];
}
point cross(point u, point v)
{
	point g;
	g.x= u.y*v.z - u.z*v.y;
	g.y= u.z*v.x - u.x*v.z;
	g.z= u.x*v.y - u.y*v.x;
	if (!bezero(g.z)) g.x/=g.z, g.y/=g.z, g.z=1;
	return g;
}
point spin(point p, double Sin, double Cos)
{
    point g;
	g.x = Cos* p.x+Sin*p.y;
	g.y = -Sin*p.x+Cos*p.y;
	g.z = p.z;
	return g;
}
void update()
{
	int i;
	for (i = 1; i <= 4; i++)
	{ 
		zd[i].x=pt[g[i]].x+vec[i].x;
		zd[i].y=pt[g[i]].y+vec[i].y;
		zd[i].z=1;
		line[i]=cross(zd[i], pt[g[i]]); 
	} 
	for (i = 1; i <= 3; i++) peak[i]=cross(line[i], line[i+1]);
	peak[4] = cross(line[4], line[1]);
	double length = dist(peak[1], peak[2]), wide = dist(peak[1], peak[4]);
	if (length*wide < ans+eps) 
	{
		ans = length*wide;
		for (i = 1; i <= 4; i++)
		 pans[i] = peak[i];
	}
}
void work()
{
	int stop, i; double  SIN, COS;
	for (i = 2, g[1] = 1; i <= top; i++) if (pt[i].y>pt[g[1]].y) g[1] = i;
	for (i = 2, g[2] = 1; i <= top; i++) if (pt[i].x>pt[g[2]].x) g[2] = i;
	for (i = 2, g[3] = 1; i <= top; i++) if (pt[i].y<pt[g[3]].y) g[3] &
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值