链接:https://ac.nowcoder.com/acm/contest/328/F
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
Special Judge, 64bit IO Format: %lld
题目描述
Rabbit和xxx获得了一个很大的蛋糕,这个蛋糕实际上是由N个点组成的凸多边形(点从1到N编号,保证没有三点共线)。
接着两个人开始分蛋糕,他们准备沿着蛋糕上两点连成的直线把蛋糕切成两份,由于Rabbit是女生,xxx总会把大的那一份分给Rabbit。现在有Q种切的方案,xxx可以选择任意一种,问xxx最多能分得多少蛋糕?
输入描述:
第一行两个整数N,Q。
接下来N行,每行两个数
x
i
,
y
i
x_i,y_i
xi,yi表示第i个点的坐标(点按逆时针顺序给出)。
接下来Q行,每行两个整数S,T表示切的两个点。
输出描述:
输出xxx最多能分得多少面积的蛋糕。
示例1
输入
4 2
0.5 0.5
10.5 0.5
10.5 10.5
0.5 10.5
1 3
4 2
输出
50.00
备注:
3
<
=
n
<
=
1
0
5
3<=n<=10^5
3<=n<=105
1
<
=
q
<
=
1
0
5
1<=q<=10^5
1<=q<=105
−
1
0
5
<
=
x
i
,
y
i
<
=
1
0
5
−10^5<=x_i,y_i<=10^5
−105<=xi,yi<=105
1
<
=
S
,
T
<
=
N
,
S
!
=
T
1<=S,T<=N,S!=T
1<=S,T<=N,S!=T
本题采用special judge,假设你的答案为a,标程答案为b,如果满足
∣
a
−
b
∣
m
a
x
(
1
,
∣
b
∣
)
≤
1
0
−
4
\frac{|a−b|}{max(1,|b|)}≤10^{−4}
max(1,∣b∣)∣a−b∣≤10−4,则认为是正确的。
思路:计算S,T两点连线分割多边形所得到的某一半的面积,可以利用叉积来求,从S点开始遍历到T点,即:
A
r
e
a
=
∑
i
=
S
+
1
T
(
x
i
−
x
s
)
(
y
i
−
1
−
y
s
)
−
(
x
i
−
1
−
x
s
)
(
y
i
−
y
s
)
Area=\sum_{i=S+1}^{T} (x_i-x_s)(y_{i-1}-y_s)-(x_{i-1}-x_s)(y_i-y_s)
Area=i=S+1∑T(xi−xs)(yi−1−ys)−(xi−1−xs)(yi−ys)
化简可得:
A
r
e
a
=
∑
i
=
S
+
1
T
x
i
y
i
−
1
−
x
i
−
1
y
i
+
x
s
(
y
i
−
y
i
−
1
)
+
y
s
(
x
i
−
1
−
x
i
)
Area=\sum_{i=S+1}^{T} x_iy_{i-1}-x_{i-1}y_i+x_s(y_i-y_{i-1})+y_s(x_{i-1}-x_i)
Area=i=S+1∑Txiyi−1−xi−1yi+xs(yi−yi−1)+ys(xi−1−xi)
然后就可以用前缀和记录了,遍历的时候再求答案即可。
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+10;
const int MOD=1e9+7;
typedef long long ll;
struct Point{double x,y;}p[MAX];
struct lenka{int s,t;}a[MAX];
Point operator-(Point A,Point B){return (Point){A.x-B.x,A.y-B.y};}
double operator^(Point A,Point B){return A.x*B.y-A.y*B.x;}
double Polyarea(Point *p,int n)
{
double area=0;
for(int i=1;i<n-1;i++)area+=(p[i]-p[0])^(p[i+1]-p[0]);
return fabs(area);
}
double A[MAX];
double B[MAX];
double sum[MAX];
int main()
{
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)scanf("%lf%lf",&p[i].x,&p[i].y);
for(int i=0;i<m;i++)scanf("%d%d",&a[i].s,&a[i].t);
memset(A,0,sizeof A);
memset(B,0,sizeof B);
memset(sum,0,sizeof sum);
for(int i=1;i<n;i++)
{
sum[i]=sum[i-1]+(p[i]^p[i-1]);
A[i]=A[i-1]+p[i].y-p[i-1].y;
B[i]=B[i-1]+p[i-1].x-p[i].x;
}
double ans=0,area=Polyarea(p,n);
for(int i=0;i<m;i++)
{
int L=min(a[i].s-1,a[i].t-1);
int R=max(a[i].s-1,a[i].t-1);
double now=fabs(sum[R]-sum[L]+p[L].x*(A[R]-A[L])+p[L].y*(B[R]-B[L]));
ans=max(ans,min(now,area-now));
}
printf("%.10f\n",ans/2.0);
return 0;
}