hdu 6127-数学

题目链接:点击打开链接


题解思路:很简单,每次选取一个点,让原点与此点连接然后再使他偏离一点点,那么这个线就将点分为左右两边,ans就可以更新 ans = max(ans,v*max(l,r)+l*r);),v是此点的值,l,r分别表示两部分各自的和,先将点分为四个象限,各个象限按斜率从小到大排序,比如当枚举到第一象限时,两部分的其中一个部分应该是第二象限+此点在第一象限斜率递增部分的点+第三象限递减的部分,其他类似。


代码:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#define inf 0x3f3f3f3f
using namespace std;
const int mx = 2e3+10;
typedef long long ll;
int n,m;
ll to[4];
struct node{
    int x,y;
    int v;
    node(){}
    node(int xx,int yy,int vv): x(xx),y(yy),v(vv){}
    bool operator < (node A)const{
        return 1.0*y/x < 1.0*A.y/A.x;
    }
}s1,s2;
vector<node> vec[4];
vector<ll>val[4];
ll get_data(ll t,ll s,node no,int p,int p1){
    int it = lower_bound(vec[p].begin(),vec[p].end(),no)-vec[p].begin();
    int ip = lower_bound(vec[p1].begin(),vec[p1].end(),no)-vec[p1].begin();
    ll l = (t + to[p] - val[p][it+1] + val[p1][ip]);
    ll r = (s + val[p][it] + to[p1] - val[p1][ip]);
    if(s1.y>0&&(p==0||p==3)) l += s1.v;
    else if(s1.y<0||(p==1||p==2)) l += s1.v;
    else r += s1.v;
    if(s2.x>0&&(p==2||p==3)) r += s2.v;
    else if(s2.x<0&&(p==0||p==1)) r += s2.v;
    else l += s2.v;
    return no.v*max(l,r)+l*r;
}
int main(){
    int t;
    scanf("%d",&t);
    int a,b,c;
    while(t--){
        scanf("%d",&n);
        for(int i=0;i<4;i++) vec[i].clear(),val[i].clear();
        s1.v = s2.v = 0;
        for(int i=1;i<=n;i++){
            scanf("%d%d%d",&a,&b,&c);
            if(a==0) s1 = node(a,b,c);
            else if(b==0) s2 = node(a,b,c);
            else if(a>0&&b>0) vec[0].push_back(node(a,b,c));
            else if(a<0&&b>0) vec[1].push_back(node(a,b,c));
            else if(a<0&&b<0) vec[2].push_back(node(a,b,c));
            else vec[3].push_back(node(a,b,c));
        }
        for(int i=0;i<4;i++){
            sort(vec[i].begin(),vec[i].end());
            ll sum = 0;
            val[i].push_back(0);
            for(int j=0;j<vec[i].size();j++){
                sum += vec[i][j].v;
                val[i].push_back(sum);
            }
        }
        ll ans = 0;
        for(int i=0;i<4;i++) to[i] = val[i].back();
        ll l = to[0]+to[3],r = to[1]+to[2];
        if(s2.x>0) l += s2.v;
        else r += s2.v;
        ans = max(ans,s1.v*max(l,r)+l*r);
        l = to[0]+to[1], r = to[2]+to[3];
        if(s1.y>0) l += s1.v;
        else r += s2.v;
        ans = max(ans,s1.v*max(l,r)+l*r);
        for(int i=0;i<vec[0].size();i++) ans = max(ans,get_data(to[1],to[3],vec[0][i],0,2));
        for(int i=0;i<vec[1].size();i++) ans = max(ans,get_data(to[2],to[0],vec[1][i],1,3));
        for(int i=0;i<vec[2].size();i++) ans = max(ans,get_data(to[3],to[1],vec[2][i],2,0));
        for(int i=0;i<vec[3].size();i++) ans = max(ans,get_data(to[0],to[2],vec[3][i],3,1));
        printf("%lld\n",ans);
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值