Codeforces 1045F: Shady Lady(凸包)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35649707/article/details/82865393

传送门

题解:
神题啊。

题目等价于如果去掉任何一个单项式,剩下的多项式无下界,则输掉比赛。

有个结论,一个多项式无下界,如果我们把每一项 x a y b x^ay^b 看做平面上的点 ( a , b ) (a,b) 的话,最后的凸包上存在一个点的横坐标或者纵坐标是奇数。

证明:

1.全是偶数则有下界。

考虑凸包上的所有点 P i P_i ,凸包内任何一个点 ( A , B ) (A,B) 可以表示为 i a i P i i a i = 1 \sum_{i}a_i P_i,\sum_i a_i =1

根据加权算术几何不等式,有:
i a i M i i M i a i = x A y B \sum_{i}a_iM_i \ge \prod_i M_i^{a_i} = |x^Ay^B|

因为 ln \ln 函数满足凸性,我们可以两边取 ln \ln 然后套用Jensen定理。
在这里插入图片描述

那么只需要把凸包上的点系数取为 n n ,就可以和凸包内部的所有点抵消并使得剩下的系数为正。

2.有奇数点则无下界。

同样先抵消掉内部的点,使得每项系数为正。

考虑任意带入一个未知数 ( t p , t q ) (-t^p,t^q) ,每项的值为为 ± a i t p a q b \pm a_it^{pa·qb} ,在 t t \rightarrow \infty 时,我们使得奇数那一项的阶最大即可。 进一步发现其实要使 ( a , b ) (a,b) ( p , q ) (p,q) 上的投影最大。 我们取 ( p , q ) (p,q) 垂直于过 ( a , b ) (a,b) 的切线即可。

现在问题变成了求去掉任意一个点后剩下的点是否有奇数点。 先做一遍凸包,如果凸包上有奇数点则无解。

否则我们可以把间距为2的两个点同时删除来判断,再做两次凸包即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}

const int N=2e5+50;
int n,m,vis[N];
struct P {
	LL x,y; int id;
	P(LL x=0,LL y=0,int id=0) : x(x),y(y),id(id) {}
 	friend inline P operator -(const P &a,const P &b) {return P(a.x-b.x,a.y-b.y);}
	friend inline LL operator *(const P &a,const P &b) {return a.x*b.y-a.y*b.x;}
	inline LL norm() {return x*x+y*y;}
} p[N],q[N];

inline void build_conv(int nn) {
	m=1;
	sort(q+1,q+nn+1,[&] (const P &a,const P &b) {return (a.x<b.x) || (a.x==b.x && a.y<b.y) || (a.x==b.x && a.y==b.y && a.id<b.id);});
	sort(q+2,q+nn+1,[&] (const P &a,const P &b) {
		LL det=(a-q[1])*(b-q[1]);
		if(det!=0) return det>0;
		return (a-q[1]).norm()<(b-q[1]).norm();
	});
	
	for(int i=2;i<=nn;i++) {
		while(m>=2 && (q[i]-q[m-1])*(q[m]-q[m-1])>=0) --m;
		q[++m]=q[i];
	}
	
	for(int i=1;i<=m;i++) if(q[i].x&1 || q[i].y&1) {puts("Ani"); exit(0);}
}

int main() {
	n=rd()+1; p[1].id=1;
	for(int i=2;i<=n;i++) p[i].x=rd(), p[i].y=rd(), p[i].id=i;
	memcpy(q+1,p+1,sizeof(P)*(n));
	build_conv(n);
	
	for(int i=2;i<=m;i+=2) vis[q[i].id]=1, vis[q[i+1].id]=2;
	
	m=0;
	for(int i=1;i<=n;i++) if(vis[i]!=2) q[++m]=p[i];
	build_conv(m);
	
	m=0;
	for(int i=1;i<=n;i++) if(vis[i]!=1) q[++m]=p[i];
	build_conv(m);
	
	puts("Borna");
}

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/82865393