NOIP2012 開車旅行 倍增

題意:兩人輪流開車,求解一些問題(題目已經講得很清楚了)
題解:

  • 首先預處理出每座城市的最近點和次近點(可以用雙向鏈表做,排序後從左到右依次找,找了之後就刪掉)
  • 然後預處理倍增,注意這時的城市已經是排序過後的了,可以轉化成原來的排列進行操作也可以直接在新排列上進行。
  • 接下來模擬就好咯

具體看代碼,這次寫的有點複雜其實是因爲我不會指針再加上作死

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN = 100001;
const double INF = 2147483647;

struct Node{
    int Height, Num;
    int Pre, Nxt;
    int Next[2];
}City[MAXN];

int N, M, x0, Head[MAXN];
int Dis_A[MAXN][20], Dis_B[MAXN][20], City_Jumper[MAXN][20];


inline int read(){
    int k = 0, f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){k = k*10 + ch - '0'; ch = getchar();}
    return k * f;
}

inline void Build_Link(){
    for(int i = 1; i <= N; i++){
        City[i].Pre = i - 1, City[i].Nxt = i + 1;
        Head[City[i].Num] = i;
    }
    City[1].Pre = City[N].Nxt = 0;
    for(int i = 1; i <= N; i++){
        int Cur = Head[i]; //從左到右的城市 
        if(City[Cur].Pre){
            Cur = City[Cur].Pre; //前一個 
            City[Head[i]].Next[0] = Cur;
            if(City[Cur].Pre){
                Cur = City[Cur].Pre; //再前一個 
                if(City[Head[i]].Height - City[Cur].Height < 
                abs(City[Head[i]].Height - City[City[Head[i]].Next[0]].Height)){

                    City[Head[i]].Next[1] = City[Head[i]].Next[0];
                    City[Head[i]].Next[0] = Cur;
                }
                else{
                    City[Head[i]].Next[1] = Cur;
                }
            }
        }
        Cur = Head[i];
        if(City[Cur].Nxt){
            Cur = City[Cur].Nxt; //後一個 
            if(City[Cur].Height - City[Head[i]].Height < 
            abs(City[Head[i]].Height - City[City[Head[i]].Next[0]].Height) 
            || !City[Head[i]].Next[0]){

                City[Head[i]].Next[1] = City[Head[i]].Next[0];
                City[Head[i]].Next[0] = Cur;
            }
            else if(City[Cur].Height - City[Head[i]].Height < 
            abs(City[Head[i]].Height - City[City[Head[i]].Next[1]].Height) 
            || !City[Head[i]].Next[1]){

                City[Head[i]].Next[1] = Cur;
            }
            if(City[Cur].Nxt){
                Cur = City[Cur].Nxt; //再後一個 
                if(City[Cur].Height - City[Head[i]].Height < 
                abs(City[Head[i]].Height - City[City[Head[i]].Next[0]].Height)){

                    City[Head[i]].Next[1] = City[Head[i]].Next[0];
                    City[Head[i]].Next[0] = Cur;
                }
                else if(City[Cur].Height - City[Head[i]].Height < 
                abs(City[Head[i]].Height - City[City[Head[i]].Next[1]].Height) 
                || !City[Head[i]].Next[1]){

                    City[Head[i]].Next[1] = Cur;
                }
            }
        }
        City[City[Head[i]].Pre].Nxt = City[Head[i]].Nxt;
        City[City[Head[i]].Nxt].Pre = City[Head[i]].Pre;
    }
    return;
}

void Build_Multiply(){
    for(int i = 1; i <= N; i++){
        City_Jumper[i][0] = City[City[i].Next[1]].Next[0];
        if(City[i].Next[0]){
            Dis_A[i][0] = abs(City[City[i].Next[1]].Height - City[i].Height);
        }
        if(City_Jumper[i][0]){
            Dis_B[i][0] = abs(City[City_Jumper[i][0]].Height - 
                                                City[City[i].Next[1]].Height);
        }
    }
    for(int j = 1; j <= 18; j++){
        for(int i = 1; i <= N; i++){
            City_Jumper[i][j] = City_Jumper[City_Jumper[i][j - 1]][j - 1];
            Dis_A[i][j] = Dis_A[i][j - 1] + Dis_A[City_Jumper[i][j - 1]][j - 1];
            Dis_B[i][j] = Dis_B[i][j - 1] + Dis_B[City_Jumper[i][j - 1]][j - 1];
        }
    }
    return;
}

int Solve_Problem_1(){
    long long DisA_Already, DisB_Already;
    int Cur, Ans_City = 0;
    double Ans_Val = INF;
    for(int i = 1; i <= N; i++){
        Cur = Head[i]; DisA_Already = DisB_Already = 0;
        for(int j = 18; j >= 0; j--){
            if(City_Jumper[Cur][j] 
            && DisA_Already + DisB_Already + Dis_A[Cur][j] + Dis_B[Cur][j] <= x0){
                DisA_Already += Dis_A[Cur][j];
                DisB_Already += Dis_B[Cur][j];
                Cur = City_Jumper[Cur][j];
            }
        }
        if(City[Cur].Next[1]
         && DisA_Already + DisB_Already + Dis_A[Cur][0] <= x0){
            DisA_Already += Dis_A[Cur][0];
        }
//      printf("%d %lf\n", Head[i], (double)DisA_Already / DisB_Already);
        if(DisB_Already && Ans_Val > (double)DisA_Already / DisB_Already){
            Ans_Val = (double)DisA_Already / DisB_Already;
            Ans_City = i;
        }
    }
    return Ans_City;
}

void Solve_Problem_2(int x0, int Cur){
    long long DisA_Already = 0, DisB_Already = 0;
    for(int j = 18; j >= 0; j--){
        if(City_Jumper[Cur][j] 
        && DisA_Already + DisB_Already + Dis_A[Cur][j] + Dis_B[Cur][j] <= x0){
            DisA_Already += Dis_A[Cur][j];
            DisB_Already += Dis_B[Cur][j];
            Cur = City_Jumper[Cur][j];
        }
    }
    if(City[Cur].Next[1] && DisA_Already + DisB_Already + Dis_A[Cur][0] <= x0){
        DisA_Already += Dis_A[Cur][0];
    }
    printf("%lld %lld\n", DisA_Already, DisB_Already);
    return;
}

inline bool cmp(Node a, Node b){
    return a.Height < b.Height;
}

int main(){
    N = read();
    for(int i = 1; i <= N; i++){
        City[i].Height = read();
        City[i].Num = i;
    }
    sort(City + 1, City + N + 1, cmp);
    Build_Link(); Build_Multiply();
    x0 = read(), M = read();
    //Solve Problem 1
    int Ans1 = Solve_Problem_1();
    printf("%d\n", Ans1);
    //Solve Problem 2
    for(int i = 1; i <= M; i++){
        int s = read(), x = read();
        Solve_Problem_2(x, Head[s]);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章