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;
}

没有更多推荐了,返回首页