[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;
}
};