[TC6194]AllWoundUp

[TC6194]AllWoundUp

题目大意:

\(A\)\(B\)两个人。\(A\)在平面上游走,\(B\)会一直盯着\(A\)看,站在\(x\)轴某个位置上不动,并随着\(A\)的运动旋转身体。\(A\)的移动轨迹是一个闭合折线,包含\(n(n\le1000)\)条线段。试最大化\(B\)逆时针旋转的次数。

思路:

\(A\)的移动轨迹将\(x\)轴分成若干段。对于同一段上的点,无论\(B\)站在哪个位置效果都是一样的。枚举\(B\)所在的位置,枚举\(A\)移动路径上的每一条边,计算\(A\)\(B\)旋转的角度即可。

源代码:

#include<cmath>
#include<vector>
#include<algorithm>
#define double long double
class AllWoundUp {
	private:
		static const int N=1000;
		struct Point {
			double x,y;
			double operator * (const Point &rhs) const {
				return x*rhs.y-y*rhs.x;
			}
			Point operator - (const Point &rhs) const {
				return (Point){x-rhs.x,y-rhs.y};
			}
			double operator ^ (const Point &rhs) const {
				return x*rhs.x+y*rhs.y;
			}
		};
		Point p[N];
		double c[N];
		int n,m;
		bool in(const double &x,const double &x1,const double &x2) const {
			return std::min(x1,x2)<=x&&x<=std::max(x1,x2);
		}
		double calc(const Point &a,const Point &b) const {
			return atan2(a*b,a^b);
		}
		int solve(const double &x0) const {
			double angle=0;
			const Point c=(Point){x0,0};
			for(register int i=0;i<n;i++) {
				const int j=(i+1)%n;
				if(p[i].y==0&&p[j].y==0&&in(x0,p[i].x,p[j].x)) return 0;
				angle+=calc(p[i]-c,p[j]-c);
			}
			return angle/M_PI/2;
		}
	public:
		int maxWind(const std::vector<int> &v1,const std::vector<int> &v2) {
			n=v1.size();
			for(register int i=0;i<n;i++) p[i].x=v1[i];
			for(register int i=0;i<n;i++) p[i].y=v2[i];
			for(register int i=0;i<n;i++) {
				const int j=(i+1)%n;
				if(p[i].y*p[j].y>0||p[i].y==p[j].y) continue;
				if(p[i].x!=p[j].x) {
					const double k=(p[i].y-p[j].y)/(p[i].x-p[j].x);
					const double b=p[i].y-k*p[i].x;
					c[m++]=-b/k;
				} else {
					c[m++]=p[i].x;
				}
			}
			if(m==0) return 0;
			std::sort(&c[0],&c[m]);
			m=std::unique(&c[0],&c[m])-c;
			int ans=0;
			for(register int i=1;i<m;i++) {
				ans=std::max(ans,solve((c[i-1]+c[i])/2));
			}
			return ans;
		}
};
posted @ 2018-07-26 18:34  skylee03  阅读(152)  评论(0编辑  收藏  举报