水果蛋糕 (二分)

水果蛋糕

[Link](第五届石家庄铁道大学程序设计竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com))

题意

给你一个矩形蛋糕,每次从上边往下边切一刀,且刀与刀之间无交点,然后给你一些水果的坐标,最后让你输出水果最多的那块,水果相同就输出面积最大的,面积相同就输出编号靠前的。

题解

对于所有的刀最右边再加一刀,方便后面操作,用Cross判断点和线的位置关系,左边Cross>0,右边Cross<0,假设某个水果p在第二块蛋糕上那么它一定在第[3,n]刀的左边[1,2]刀的右边,具有二段性因此可以二分,然后都是梯形存一下上下边长即可,最后排个序即可。

Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <unordered_map>
#include <cmath> 
#include <stack>
#include <iomanip>
#include <deque> 
#include <sstream>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
#define tpyeinput int
inline char nc() {static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;}
inline void read(tpyeinput &sum) {char ch=nc();sum=0;while(!(ch>='0'&&ch<='9')) ch=nc();while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+(ch-48),ch=nc();}
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
    e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int sgn(double x) {
    if (fabs(x) < eps) return 0;
    if (x < 0) return -1;
    return 1;
}
struct Point {
double x, y;
Point() {}
Point (double _x, double _y) {
x = _x, y = _y;
}
void input() {
scanf("%lf%lf", &x, &y);
}
void output() {
printf("%.2lf %.2lf", x, y);
}
bool operator ==(Point b) const{
return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
}
bool operator <(Point b) const{
return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
}
Point operator -(const Point &b) const{
return Point(x - b.x, y - b.y);
}
Point operator +(const Point &b) const{
return Point(x + b.x, y + b.y);
}
Point operator *(const double &t) const{
return Point(x * t, y * t);
}
Point operator /(const double &t) const{
return Point(x / t, y / t);
}
//cross
double operator ^(const Point &b) const{
return x * b.y - y * b.x;
}
// dot
double operator *(const Point &b) const{
return x * b.x + y * b.y;
}
double len() {
return hypot(x, y);
}
double len2() {
return x * x + y * y;
}
double distance(Point p) {
return hypot(x - p.x, y - p.y);
}
// pa pa 夹角 
double rad(Point a, Point b) {
Point p = *this;
return fabs(atan2(fabs((a - p) ^ (b - p)), (a - p) * (b - p)));
}
// 转化为长度为r的向量
Point trunc(double r) {
double l = len();
if (!sgn(l)) return *this;
r /= l;
return Point(x * r, y * r);
}
//逆时针旋转90度
Point rotleft() {
return Point(-y, x);
}
//顺时针旋转90度
Point rotright() {
return Point(y, -x);
}
// 绕着p点逆时针旋转 rad度
Point rotate(Point p, double rad) {
Point v = (*this) - p;
double c = cos(rad), s = sin(rad);
return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c);
}
};
typedef Point Vector;
Point U[N], D[N];
struct Node {
    int cnt, area, id;
}res[N];
bool cmp(Node a, Node b) {
    if (a.cnt != b.cnt) return a.cnt > b.cnt;
    else if (a.area != b.area) return a.area > b.area;
    else return a.id < b.id;
}
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> n >> m;
    double sx, sy, prux = 0, prdx = 0; cin >> sx >> sy;
    for (int i = 1; i <= n; i ++ ) {
        cin >> U[i].x >> D[i].x;
        res[i].area = U[i].x + D[i].x;
        U[i].x += prux, D[i].x += prdx;
        U[i].y = sy, D[i].y = 0;
        prux = U[i].x, prdx = D[i].x;
        res[i].id = i;
    } 
    U[n + 1] = {sx, sy}, D[n + 1] = {sx, 0}, res[n + 1].id = n + 1, res[n + 1].area = sx * 2 - U[n].x - D[n].x;
    for (int i = 0; i < m; i ++ ) {
        double x, y; cin >> x >> y;
        int l = 1, r = n + 1;
        while (l < r) {
            int mid = l + r >> 1;
            if (sgn((U[mid] - D[mid]) ^ (Point(x, y) - D[mid])) > 0) r = mid;
            else l = mid + 1;
        }
        res[l].cnt ++;
    }
    sort(res + 1, res + n + 2, cmp);
    cout << res[1].id << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值