BZOJ153/POI2005 A Journey to Mars

確定了起點和方向之後,旅行的過程就確定了,到達i點的花費<=到i點之間的油料數量就是題目的限制條件.
由於是繞圈問題,我們可以把序列複製相接,轉化成序列上的問題.
sum[j] 表示到j 之前所得油料數量dis[j] 表示1到j 的距離,對於起點i,保證每個j<=i+n 都有:
sum[j]sum[i]>=dis[j]dis[i]
移項得到:sum[j]dis[j]>=sum[i]dis[i] .
那麼只要保證sum[j]dis[j] 的最小值滿足條件即可.
問題就轉化爲了求區間最值問題,根據起點的移動規律,可以確定每次j 的範圍只往前移動了1,那麼我們可以通過單調隊列來求出最值,從而得到答案

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int M=2e6+5;
int d[M],p[M],n,Q[M],id[M];
ll sum[M],dis[M];
bool f[M];
inline void rd(int &res){
    res=0;char c;
    while(c=getchar(),c<48);
    do res=(res<<1)+(res<<3)+(c^48);
    while(c=getchar(),c>=48);
}
void solve(int s){
    int i,j,k;
    sum[0]=0;
    for(i=1;i<=n*2;i++){
        sum[i]=sum[i-1]+p[i-1];//sum[i]表示從1到i能得到的油量,不包括i 

        dis[i]=dis[i-1]+d[i+s];//從1到i的距離和 
    }
    /*
        for i
        j->[i+1,i+n]  sum[j]-sum[i]>=dis[j]-dis[i]
                      sum[j]-dis[j]>=sum[i]-dis[i].
                      Min(sum[j]-dis[j])>=sum[i]-dis[i]
        Push k -> pop val[j]>=val[k]
    */
    int L=0,R=-1;
    for(i=2;i<=n+1;i++){
        while(R>=L&&sum[Q[R]]-dis[Q[R]]>=sum[i]-dis[i])R--;
        Q[++R]=i;
    }
    for(i=1;i<=n;i++){//判斷i點是否可行 
        while(L<=R&&Q[L]<i+1)L++;
        if(L<=R){
            k=Q[L];
            if(sum[k]-dis[k]>=sum[i]-dis[i])f[id[i]]=true;
        }
        while(R>=L&&sum[Q[R]]-dis[Q[R]]>=sum[i+n+1]-dis[i+n+1])R--;
        Q[++R]=i+n+1;
    }
}
int main(){
    int i,j,k;
    rd(n);
    for(i=1;i<=n;i++){
        id[i]=i;
        rd(p[i]),rd(d[i]);
        p[i+n]=p[i];
        d[i+n]=d[i];
    }
    solve(-1);
    for(i=1;i<=n;i++){
        swap(d[i],d[2*n-i+1]);
        swap(p[i],p[2*n-i+1]);
        id[i]=n-i+1;
    }
    solve(0);
    for(i=1;i<=n;i++){
        if(f[i])puts("TAK");
        else puts("NIE");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章