当前位置: 代码迷 >> 综合 >> 【乱搞】[Atcoder Grand Contest 022 ]D Shopping
  详细解决方案

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

热度:113   发布时间:2023-09-27 07:42:43.0

题意:

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


分析:

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

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

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

考虑如何求出答案:我们从最左边出发,若从左边经过一个点,若x=0x=0,那么可以不增加代价,反向离开;若x=1x=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)最多只有一个。

再考虑剩下的答案如何求,设剩下的点有SS个。很显然,只有当最右端没有被匹配,并且为(0,1)或(0,0)时,答案为 S 否则,均为S+1S+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;elses[i].first=1;if(t[i]<=2ll*x[i])s[i].second=0;elses[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;}elseq[0].push(i);}elseq[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;elseres=sum;}if(del[n-1]==1)res=sum+1;ans+=res*2ll*L;PF("%lld",ans);
} 
  相关解决方案