【乱搞】[Atcoder Grand Contest 022 ]D Shopping

题意:

有n个火车站,位于一条坐标轴上,坐标为 x i ,现在,葱花从原点出发,到每个火车站的商店购物,并最后回到家中。已知每个商店的购物时间分别为 t i
但这个火车非常的扯,它只有1班车,还只能从原点到点(L,0)以1的速度横向鬼畜。葱花只能乘火车移动,只有在火车经过它所在的车站时才能上车,只有在火车到达它想到的车站时才能下车。
求葱花购物完回家的最断时间。
n 300000


分析:

显然,最终的时间一定为 x × 2 L (x表示火车在这段时间的鬼畜次数)
并且,很显然当葱花购物完毕后,必然会在第一次车到站时上车。
然后,对每个 t i 2 L ,我们可以直接将其 m o d 2 L

用一个二元组(x,y)来表示每个点:
t i 2 ( L x i ) x = 0 否则 x = 1 ,表示:若车从左边来,那么当x=0时,它会从左边离开,当x=1时从右边离开。
同样地
t i 2 x i , y = 0 否则 y = 1 ,表示,若车从右边来,那么当 y = 0 时,它会从右边离开,否则从左边离开。

若出现了 t i = 0 的情况(即之前取模之后变为了0),根据定义应该修改为(1,1)。
很容易发现,一定不会出现 ( 1 , 0 ) ( 0 , 1 ) 之前:因为 L x i 是递减的, x i 是递增的,所以如果存在一个值x,使得 2 x i t i > 2 ( L x i ) ,那么不可能当 x i 更大, ( L x i ) 更小时, 2 x i < t i 2 ( L x i )

考虑如何求出答案:我们从最左边出发,若从左边经过一个点,若 x = 0 ,那么可以不增加代价,反向离开;若 x = 1 ,那么可以增加1的代价,正向离开。对从右边经过是同理的。每到达一次端点(原点或(L,0)),代价再次+1。显然多走0的点是最优的。并且对于(1,1)的点,无论怎么经过它,代价都要+1

所以,先删去所有(1,1)的点,再将不同的点的0配对,即(1,0)或(0,0)与在它右边的(0,1)或(0,0)配对。并删去配对的点,最后一定形成了形如:(0,1)(0,1)……(0,0)(1,0)(1,0)……的样子,中间的(0,0)最多只有一个。

再考虑剩下的答案如何求,设剩下的点有 S 个。很显然,只有当最右端没有被匹配,并且为(0,1)或(0,0)时,答案为 S 否则,均为 S + 1
证明很简单,若最右端为(0,1)或(0,0),那么就可以不经过最右端的点,直接返回左边,而如果最右端之前被匹配过或为(1,0),那么必然会经过最右端的点,所以代价要+1

注意实现的时候要使得右端点尽可能不被匹配到,并且要注意最大匹配的写法(贪心思路O(n)做)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<stack>
#define SF scanf
#define PF printf
#define MAXN 300010
using namespace std;
typedef long long ll;
int n;
ll L,ans,x[MAXN],t[MAXN];
pair<int,int> s[MAXN];
stack<int> q[2];
bool del[MAXN];
int main(){
    //freopen("datax.in","r",stdin);
    //freopen("data.out","w",stdout);
    SF("%d%lld",&n,&L);
    for(int i=0;i<n;i++)
        SF("%lld",&x[i]);
    for(int i=0;i<n;i++){
        SF("%lld",&t[i]);
        ans+=(t[i]/(2ll*L))*2ll*L;
        t[i]%=(2ll*L);
    }
    //PF("[%lld]",ans);
    bool flag=0;
    for(int i=0;i<n;i++){
        if(t[i]!=0){
            flag=1;
            if(t[i]<=2ll*(L-x[i]))
                s[i].first=0;
            else
                s[i].first=1;
            if(t[i]<=2ll*x[i])
                s[i].second=0;
            else
                s[i].second=1;
        }
        else{
            s[i].first=s[i].second=1;
        }
    }
    for(int i=0;i<n;i++)
        if(s[i].first==1&&s[i].second==1){
            del[i]=1;
            if(t[i]!=0)
                ans+=2ll*L; 
            //PF("********(%lld %lld)******",t[i],x[i]);
        }
    for(int i=0;i<n-1;i++){
        if(del[i]==1)
            continue;
        if(s[i].first==0&&s[i].second==1){
            if(!q[1].empty()){
                del[q[1].top()]=1;
                del[i]=1;
                q[1].pop();
                ans+=2ll*L;
            }
            else if(!q[0].empty()){
                del[q[0].top()]=1;
                del[i]=1;
                q[0].pop();
                ans+=2ll*L;
            }
        }
        else if(s[i].second==0){
            q[s[i].first].push(i);
        }
    }
    while(!q[1].empty())
        q[1].pop();
    while(!q[0].empty())
        q[0].pop();
    //PF("{%lld}",ans);
    for(int i=0;i<n-1;i++){
        if(del[i]==1||(s[i].first==0&&s[i].second==1))
            continue;
        if(s[i].first==0){
            if(!q[1].empty()){
                del[i]=1;
                del[q[1].top()]=1;
                q[1].pop();
                ans+=2ll*L;
            }
            else if(!q[0].empty()){
                del[i]=1;
                del[q[0].top()]=1;
                q[0].pop();
                ans+=2ll*L;
            }
            else
                q[0].push(i);
        }
        else
            q[1].push(i);
    }
    if(s[n-1].first==0&&del[n-1]==0){
        for(int i=0;i<n-1;i++)
            if(del[i]==0&&s[i].second==0){
                del[i]=1;
                del[n-1]=1;
                ans+=2ll*L;
                break;
            }
    }
    /*for(int i=0;i<n;i++)
        PF("[%d %d %d]\n",s[i].first,s[i].second,del[i]);
    PF("{%lld}",ans);*/
    ll res=0,sum=0;
    for(int i=0;i<n;i++)
        if(del[i]==0)
            sum++;
    if(del[n-1]==0){
        if(s[n-1].first==1&&s[n-1].second==0)
            res=sum+1;
        else
            res=sum;
    }
    if(del[n-1]==1)
        res=sum+1;
    ans+=res*2ll*L;
    PF("%lld",ans);
} 

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/79836152