The 2015 ACM-ICPC Asia Beijing Regional A.Xiongnu's Land

題目鏈接:UVA 7261(A)
題意:在二維座標系第一象限中,將一塊頂點在原點邊長爲R的正方形土地用直線x=n一分爲二,左側分給Wei,右側分給Huo。
土地中包含N個綠洲,每個綠洲是一個矩形,其位置和大小用四元組(L,T,W,H)表示,其中(L,T)爲其左上方頂點的座標,W,H爲其寬度和高度。綠洲互不重疊。
求滿足以下條件的一條劃分直線(直線方程 x=n,0<=n<=R,n取整數):
(1)二人各自所得土地中綠洲面積應滿足Wei>=Huo 且二者之差達到最小;
(2)在滿足(1)的基礎上,Wei的土地面積越大越好。

題解:二分(線性掃描也可以)。
我把L排了個序,而且用dp[i]標記了x = i這條線左邊有多少個綠洲,方便自己計算線x = i左邊的綠洲面積,這個代碼寫的累贅了,跑了123ms。可以不需要這些東西,具體讀者可以參考別人的博客,可能跑的要快幾十ms。
關鍵是二分,這是大家都一樣的。需要兩個二分,第一個二分得到l,目標是得到 線左綠洲面積剛好 >= 線右綠洲面積 時的 綠洲面積;第二個二分,在第一個基礎上,使得r儘可能大,且線左綠洲面積不增加,r即爲答案。

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#define Max(a,b) a>b?a:b
#define Min(a,b) a>b?b:a
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
int dir[4][2]= {{1,0},{-1,0},{0,1},{0,-1}};
const double eps = 1e-6;
const double Pi = acos(-1.0);
const int INF=0x3f3f3f3f;
const int maxn = 1e6+10;
ll sum,R,summ;
int dp[maxn];
struct Oasis{
    ll L,T,W,H;
    Oasis(){}
    Oasis(ll l,ll t,ll w,ll h): L(l),T(t),W(w),H(h){}
    bool operator < (const Oasis &cmp) const {
        return L < cmp.L;
    }
}arr[maxn];

ll calcu(ll ind){
    ll summ = 0;
    for(int i = 0; i < dp[ind]; i++){
        if(ind < arr[i].L+arr[i].W){
            summ += (ind - arr[i].L) * arr[i].H;
        }else{
            summ += arr[i].W * arr[i].H;
        }
    }
    return summ;
}

ll solve(){
    ll l = 0, r = R, mid;
    ll summ1,summ2;
    while(l <= r){
        mid = (l + r) / 2;
        summ1 = calcu(mid);
        if(summ1 < sum - summ1){
            l = mid + 1;
        }else{
            r = mid - 1;
        }
    }
    ll tmp = calcu(l);
    l = 0, r = R;
    while(l <= r){
        mid = (l + r) / 2;
        if(calcu(mid) > tmp){
            r = mid - 1;
        }else{
            l = mid + 1;
        }
    }
    return r;
}

int main(){
    int T,n,cnt;
    ll l,t,w,h;
//    freopen("F://duipai//data.txt","r",stdin);
//    freopen("F://duipai//out2.txt","w",stdout);
    scanf("%d",&T);
    while(T--){
        mem(dp,0);
        mem(arr,0);
        sum = 0;
        scanf("%lld",&R);
        scanf("%d",&n);
        for(int i = 0;i < n; i++){
            scanf("%lld%lld%lld%lld",&l,&t,&w,&h);
            arr[i] = Oasis(l,t,w,h);
            dp[l]++;
            sum = sum + w*h;
        }
        for(int i = 1; i < maxn; i++){
            dp[i] = dp[i] + dp[i-1];
        }
        sort(arr,arr+n);
        ll ans = solve();
        if(ans > R){
            ans = R;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章