[JSOI2018]战争(闵可夫斯基和)

害怕,可怜几何题
果然不会
题目就是说给你两个凸包,每次询问给你一个向量 \(c\) 问你能不能从两个凸包 \(A\) , \(B\) 里分别找到一个点 \(a\) , \(b\) 满足 \(a+c=b\)
考虑怎样的向量可以满足。
发现只有让B中的每一个点-A中的每一个点的集合中的向量可以满足。因为把上面的式子化一下就是 \(c=b-a\)
凸包B中的点集减去凸包A中的点集。这不是闵可夫斯基和吗?
所以我们把两个凸包的闵可夫斯基和求出,然后每一个询问查看给的向量在不在闵可夫斯基和中即可。
代码极丑,不过我判向量是不是在凸包里是把凸包切成上下两个凸包,然后分类讨论求的。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define int long long
const int N=501000;
int read(){
    int sum=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    return sum*f;
}
int top1,top2,top;
struct node{
    int x,y;
    node (int xx=0,int yy=0){
        x=xx,y=yy;
    }
}stack1[N],stack2[N],a[N],b[N],ans[N],ans1[N];
node operator +(node a,node b){
    return node(a.x+b.x,a.y+b.y);
}
node operator -(node a,node b){
    return node(a.x-b.x,a.y-b.y);
}
bool cmp(node a,node b){
    if(a.x==b.x)return a.y<b.y;
    else return a.x<b.x;
}
int chaji(node a,node b){
    return a.x*b.y-a.y*b.x;
}
bool judge(node a,node b,node c){
    return chaji(b-c,a-b)<=0;
}
int n,m;
void tubao1(){
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=n;i++){
        while(top1>1&&judge(a[i],stack1[top1],stack1[top1-1]))top1--;
        stack1[++top1]=a[i];
    }
    int k=top1;
    for(int i=n-1;i>=1;i--){
        while(top1>k&&judge(a[i],stack1[top1],stack1[top1-1]))top1--;
        stack1[++top1]=a[i];
    }
    top1--;
}
void tubao2(){
    sort(b+1,b+1+m,cmp);
    for(int i=1;i<=m;i++){
        while(top2>1&&judge(b[i],stack2[top2],stack2[top2-1]))top2--;
        stack2[++top2]=b[i];
    }
    int k=top2;
    for(int i=m-1;i>=1;i--){
        while(top2>k&&judge(b[i],stack2[top2],stack2[top2-1]))top2--;
        stack2[++top2]=b[i];
    }
    top2--;
}
void sum(){
    for(int i=1;i<=top1;i++)a[i]=stack1[i+1]-stack1[i];
    for(int i=1;i<=top2;i++)b[i]=stack2[i+1]-stack2[i];
    ans[top=1]=stack1[1]+stack2[1];
    int now1=1,now2=1;
    while(now1<=top1&&now2<=top2)top++,ans[top]=ans[top-1]+(chaji(a[now1],b[now2])>=0?a[now1++]:b[now2++]);
    while(now1<=top1)top++,ans[top]=ans[top-1]+a[now1++];
    while(now2<=top2)top++,ans[top]=ans[top-1]+b[now2++];
    top--;
}
bool in(node x){
    if(x.x<ans[1].x||x.x>ans[top1].x)return false;
    if(x.x==ans[1].x){
        if(x.y>=ans[1].y&&x.y<=ans1[1].y)return true;
        else return false;
    }
    if(x.x==ans[top1].x){
        if(x.y>=ans[top1].y&&x.y<=ans1[top2].y)return true;
        else return false;
    }
    int A=lower_bound(ans+1,ans+1+top1,x,cmp)-ans;
    int B=lower_bound(ans1+1,ans1+1+top2,x,cmp)-ans1;
    if(chaji(ans1[B]-x,ans1[B-1]-x)>=0&&chaji(ans[A-1]-x,ans[A]-x)>=0)return true;
    else return false;
}
int q;
signed main(){
    n=read();m=read();q=read();
    for(int i=1;i<=n;i++)a[i].x=read(),a[i].y=read();
    tubao1();
    for(int i=1;i<=m;i++)b[i].x=-read(),b[i].y=-read();
    tubao2();
    sum();
    for(int i=1;i<=top;i++)
        if(ans[i+1].x<ans[i].x){top1=i;break;}
    for(int i=top1;i<=top+1;i++)
        ans1[i-top1+1]=ans[i];
    top2=top+1-top1+1;
    while(ans[top1-1].x==ans[top1].x)top1--;
    while(ans1[top2-1].x==ans1[top2].x)top2--;
    for(int i=1;i<=top2/2ll;i++)swap(ans1[i],ans1[top2-i+1]);
    while(q--){
        int A=read(),B=read();
        node x=node(A,B);
        if(in(x))printf("1\n");
        else printf("0\n");
    }
    return 0;
}

转载于:https://www.cnblogs.com/Xu-daxia/p/10611378.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用[1],dp[u][j]表示在u子树中选取恰好j个人时能获得的最大价值。而根据引用,该问题的时间复杂度为O(log2​104×nm)。 对于洛谷P2143 [JSOI2010] 巨额奖金问题,我们可以使用动态规划来解决。具体步骤如下: 1. 首先,我们需要构建一棵树来表示员工之间的关系。树的根节点表示公司的总经理,其他节点表示员工。每个节点都有一个权值,表示该员工的奖金金额。 2. 接下来,我们可以使用动态规划来计算每个节点的dp值。对于每个节点u,我们可以考虑两种情况: - 如果选择节点u,则dp[u][j] = dp[v][j-1] + value[u],其中v是u的子节点,value[u]表示节点u的奖金金额。 - 如果不选择节点u,则dp[u][j] = max(dp[v][j]),其中v是u的子节点。 3. 最后,我们可以通过遍历树的所有节点,计算出dp[u][j]的最大值,即为所求的巨额奖金。 下面是一个示例代码,演示了如何使用动态规划来解决洛谷P2143 [JSOI2010] 巨额奖金问题: ```python # 构建树的数据结构 class Node: def __init__(self, value): self.value = value self.children = [] # 动态规划求解最大奖金 def max_bonus(root, j): dp = [[0] * (j+1) for _ in range(len(root)+1)] def dfs(node): if not node: return for child in node.children: dfs(child) for k in range(j, 0, -1): dp[node.value][k] = max(dp[node.value][k], dp[node.value][k-1] + node.value) for child in node.children: for k in range(j, 0, -1): for l in range(k-1, -1, -1): dp[node.value][k] = max(dp[node.value][k], dp[node.value][k-l-1] + dp[child.value][l]) dfs(root) return dp[root.value][j] # 构建树 root = Node(1) root.children.append(Node(2)) root.children.append(Node(3)) root.children[0].children.append(Node(4)) root.children[0].children.append(Node(5)) root.children[1].children.append(Node(6)) # 求解最大奖金 j = 3 max_bonus_value = max_bonus(root, j) print("最大奖金为:", max_bonus_value) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值