NOIP2012 D1T3 開車旅行

md這sb題怎麼這麼墨跡,在心裏默默地罵出題人

咳咳
題目大意:
在一個數軸上,每個點有互不相同的點權,規定兩點之間距離爲兩個的點權的差的絕對值,現在從最左面出發,只能向右走,交替的走次大值和最大值,然後現在問在規定的距離內,兩個人向右走,兩個人分別能走多少路

Solution
思博倍增,普及組小孩都會
首先,暴力的話可以直接預處理出下一個點能走的最大值和次大值都是誰,然後暴力的走下去。
然後我們發現這個東西可以倍增,我們先維護出一個點能向右走的最大值和次大值,然後我們就可以玩了
pos(i,j) 表示從i ,向後2j 步的位置是誰,顯然pos(i,0)=nextsec(i).pos(i,1)=nextfir(pos(i,0)) ,而對於j>=2 的情況就直接有pos(i,j)=pos(pos(i,j1),j1)
然後直接倍增,在倍增處理位置的同時維護一下分別走的距離,然後玩一下就行了。

在維護最大值次大值的時候可以用set ,當然其實也是可以用雙向鏈表的

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <cmath>
const int N = 100000+5;

typedef long long LL;
LL inf = 1e15;
using namespace std;

struct cmps
{
    int val,now,pos;
    cmps () {}
    cmps (LL _val,int _now,int _pos):val(_val),now(_now),pos(_pos){}
    bool operator < (const cmps &z)const
    {
        return now ^ z.now ? now < z.now : val < z.val;
    }
}tmp[5];

struct Lux
{
    int pos;
    int val;
    bool operator < (const Lux & z)const
    {
        return val ^ z.val ? val < z.val : pos < z.pos;
    }
}a[N];

int L[N];
int R[N];
int T[N];

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

int next_Fir[N];
int next_Sec[N];
int next[N][20];
LL   dis[N][20];
LL  disA[N][20];

LL H[N];

bool equal(double A,double B)
{
    return fabs(A-B) < (1e-9)*max(A,B);
}

double calc(double A,double B)
{
    if(equal(B,0))
        return 1e9;
    else return A / B;
}

int main()
{
//  freopen("27.in", "r", stdin);
    int n = read();
    for(int i=1;i<=n;++i) a[i].pos = i ,H[i] =  a[i].val = read();

    sort(a+1,a+n+1);
    for(int i=1;i<=n;++i)
    {
        L[i] = i - 1;
        R[i] = i + 1;
        T[a[i].pos] = i;
    }

    H[0] = H[n+1] = inf;


    for(int t=1;t<=n;++t)
    {
        int tot = 0;
        int i = T[t];
        if(L[i]) tmp[++tot] = cmps(a[L[i]].val,labs(a[i].val - a[L[i]].val),a[L[i]].pos);
        if(L[L[i]]) tmp[++tot] = cmps(a[L[L[i]]].val,labs(a[i].val - a[L[L[i]]].val),a[L[L[i]]].pos);
        if(R[i] <= n) tmp[++tot] = cmps(a[R[i]].val,labs(-a[i].val + a[R[i]].val),a[R[i]].pos);
        if(R[R[i]] <= n) tmp[++tot] = cmps(a[R[R[i]]].val,labs(-a[i].val + a[R[R[i]]].val),a[R[R[i]]].pos);
        if(tot == 0)continue;
        if(tot == 1){next_Fir[a[i].pos] = tmp[1].pos;L[R[i]] = L[i];R[L[i]] = R[i];continue;}
        sort(tmp+1,tmp+tot+1);
        next_Fir[a[i].pos] = tmp[1].pos;
        next_Sec[a[i].pos] = tmp[2].pos;
        L[R[i]] = L[i];
        R[L[i]] = R[i];
    }

    for(int i=1;i<=n;++i)
    {
        next[i][0] = next_Sec[i];
        next[i][1] = next_Fir[next[i][0]];
        dis[i][0] = labs(H[next[i][0]] - H[i]);
        dis[i][1] = dis[i][0] + labs(H[next[i][1]] - H[next[i][0]]);
        disA[i][0] = disA[i][1] = dis[i][0];
    }

    for(int j=2;j<=18;++j)
        for(int i=1;i<=n;++i)
        {
            next[i][j] = next[next[i][j-1]][j-1];
            dis[i][j] = dis[next[i][j-1]][j-1] + dis[i][j-1];
            disA[i][j] = disA[next[i][j-1]][j-1] + disA[i][j-1];
        }

    for(int j=0;j<=18;++j)
        for(int i=1;i<=n;++i)
            if(!next[i][j])
                next[i][j] = n + 1,dis[i][j] = 1e9+5;

    LL lmt = read();

    int pos = 0;
    double ans = 1e16;


    for(int i=1;i<=n;++i){
        LL tmp = 0;
        int x = i;
        LL tlmt = lmt;
        LL all = 0;
        for(int j=18;j>=0 && x!=n+1;--j)
            if(lmt >= dis[x][j])
            {
                lmt -= dis[x][j];
                tmp += disA[x][j] ;
                all += dis[x][j];
                x = next[x][j];
            }
        LL tmpB = all - tmp;
        LL tmpA = tmp;
        double tt = calc(tmpA,tmpB);
//      printf("%.2lf\n",tt);
        if(equal(tt,ans))
        {
            if(H[pos] < H[i])
                pos = i;
        }
        else if(tt < ans)
        {
            ans = tt;
            pos = i;
        }
        lmt = tlmt;
    }

    cout << pos << endl;

    int m = read();
    while(m--){
        LL tmp = 0;
        int x = read();
        lmt = read();
        LL all = 0;
        for(int j=18;j>=0 && x!=n+1;--j){
            if(lmt >= dis[x][j])
            {
                lmt -= dis[x][j];
                all += dis[x][j];
                tmp += disA[x][j];
                x = next[x][j];
            }
        //  cout << x << " " << tmp << endl;
        } 
        LL tmpB = all - tmp;
        LL tmpA = tmp;  
        printf("%lld %lld\n",tmpA,tmpB);
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章