1. 程式人生 > >HDU6127-Hard challenge

HDU6127-Hard challenge

HDU6127 原題傳送門
題意:給定n個平面座標點,任意兩個點兩兩連線(連線不過原點),每個點帶權值,然後任意兩個點所連成的線段的權值為點權的乘積,找一條過原點的直線,要求它所穿過的線段的權值和最大,輸出最大權值和

官方題解:對於一條直線,線段權值和實際上就等於其兩邊點權和的乘積,所以把所有點按極角排個序,然後掃一圈就好了。(喵了個咪)

個人理解:一直線把所有的點分為直線上方和直線下方兩部分,然後每一個點都跟對面的所有點銜接,產生的權值就是對面的權值和乘該點的權值,因此這條直線的經過的線段的權值和就是一部分點的權值和乘於另外一部分的權值和。

而每一個點跟原點的連線都可以將所有點分為兩部分(題意不存在兩點連線過原點),因此就是直接從點出發找直線將點分為兩部分,但如果是列舉每個點再暴力列舉把所有點兩部分的話,這樣的複雜度是O(n^2), 因此需要對點進行處理也就是極角排序O(n logn)。

排完了序,所有的點就按照逆時針擺好,sum是所有點的權值和,用up記錄直線上方的權值和(把當前點也歸到直線上放的部分),列舉所有的點和原點連線作為劃分的標準有pos記錄每次劃分到哪個點,然後列舉下一個點的時候, 把上一個點分到另一部分即up減去上一個點的權值,而pos繼續掃,最後就是一個ans一直維護up*(sum-up)的最大值,然後輸出ans

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5+5e4;

struct point
{
    ll x, y, val;
}a[N];

ll max(ll a, ll b)
{
    return
a>b?a:b; } ll Xmul(point a, point b) {//叉積排序 return a.x*b.y-a.y*b.x; } bool cmp(point a,point b) { return Xmul(a, b)>0; } int main() { ios::sync_with_stdio(false); int t; cin>>t; while(t--) { int n; cin>>n; ll ans = 0, pos = 1, up = 0, sum = 0
; for(int i = 0; i < n; i ++) { cin>>a[i].x>>a[i].y>>a[i].val; sum += a[i].val; } sort(a, a+n, cmp); up += a[0].val; for(int i = 0; i < n; i ++) { while(cmp(a[i], a[pos])) {//a[i]跟原點連線為當前直線 up += a[pos].val; pos ++; pos %= n;//pos會掃兩圈 } ans = max(ans, up*(sum-up)); up -= a[i].val; } cout<<ans<<endl; } return 0; }

順便附上標程,上面的程式碼是以叉積的大小作為極角的排序規則,而下面的程式碼是以tan角作為排序規則,想知道差異在哪不妨把排完序的點輸出來看看

#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<cstdio>
#include<cassert>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const double PI=acos(-1);
typedef long long ll;
typedef pair<int,int> pi;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define rep(i,a,b) for (int i=(a);i<=(b);i++)
#define per(i,a,b) for (int i=(a);i>=(b);i--)
#define Rep(i,a,b) for (int i=(a);i<(b);i++)
#define Per(i,a,b) for (int i=(a);i>(b);i--)
//debug
#define deb printf("begin\n");
#define dee printf("end\n");
#define def printf("find\n");
#define dey printf("Yes\n");
#define den printf("No\n");
#define dew printf("wrong\n");
void read(int&x){
    x=0;int f=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if (ch=='-')f=-1,ch=getchar();
    while (ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    x*=f;
}
//--------------------------head--------------------------//

#define eps 1e-9
#define maxn 200005
struct Node{
    double x,y,ang;int v;Node(){}Node(double x,double y,int v):x(x),y(y),v(v){}
    void readin(){scanf("%lf%lf\n",&x,&y);read(v);ang=atan(y/x);}
    bool operator <(const Node&p)const{return ang<p.ang;}
}p[maxn];
int n,T;double x[maxn],y[maxn];int v[maxn];
ll sumL,sumR,ans;
void work(){
    read(n);rep(i,1,n)p[i].readin();sort(p+1,p+n+1);
    sumL=sumR=ans=0;rep(i,1,n)if (p[i].x>eps)sumL+=p[i].v;else sumR+=p[i].v;ans=sumL*sumR;
    rep(i,1,n){
        if (p[i].x>0)sumL-=p[i].v,sumR+=p[i].v;else sumL+=p[i].v,sumR-=p[i].v;
        ans=max(ans,sumL*sumR);
    }
    printf("%lld\n",ans);
}
int main(){
    freopen("H.in","r",stdin);
    freopen("H_.out","w",stdout);
    read(T);while (T--)work();return 0;
}