zoukankan      html  css  js  c++  java
  • [atAGC022D]Shopping

    称0到$L$的方向为左,同时为了方便,可以假设$0<t_{i}le 2L$

    当我们确定是进入店中的方向,根据这个店的位置以及购物时间,不难确定出来时火车经过0或$L$的次数,由于$0<t_{i}le 2L$,因此总共至少有一次且分别不超过1次,即分以下三类讨论:

    1.经过0未经过$L$,在该位置上标记为1

    2.经过$L$未经过0,在该位置上标记为-1

    3.经过$L$且经过0,在该位置上标记为1、-1

    同时,对于坐在车上经过0或$L$,也可以看作0或$L$上有一个商店,即在0上记录1,$L$上记录-1

    (特别的,对于初始位于0不记录,对于最后到达0记录)

    最后,将0到$L$每一个位置上的序列连结起来,即构成一个由1、-1构成的序列

    考虑这个序列的意义,每一个1即表示该次火车到0时自己所处的位置,-1类似

    下面来考虑火车,对于每一趟,确定一对1和-1(即该次其到0和$L$时我的位置),并将这一对1和-1删去,不难发现要保证:

    1.删去的1(的位置)必须在该对的-1之前,删去的-1必须在上一对(若存在)删去的1之后

    (可以理解一下,否则我仍然在上一次的商店中)

    2.最后一次删去的1必须在位置0上或为空(即最后要返回0)

    同时,这一方案的所需时间为这个序列长度*L(每一个1或-1恰好对应$L$的路程),因此可以看作构造最短的1和-1的序列,使得其可以以上述方法删除:

    先考虑上述删除的真正限制,首先仅考虑每一次1在-1,即要求前缀和非负,同时由于成对匹配,即1和-1的数量相同,整体前缀和为0

    (可以以括号序列的方式理解,但注意,我们并不要求其1和-1要以括号序列的配对方式删除,即若将删去的一对括号看成一个区间,是可以有交的,那么就会有多种解)

    同时,这并不充分,我们还要求其在0上存在1,且除去空前缀和整体以外,前缀和严格大于0

    典型的例子是${1,-1,1,-1}$,由于第一个1要最后删除,那么一定先删除3和4上的1和-1,那么根据第二点删去的-1必须在上一对删去的1之后,是无法删除第2个位置的

    关于这个的证明,套用上面这个例子就可以了,对于前缀和为0的前缀,最左边的1必然要与这之前的-1匹配,由于这是最后一次匹配,那么上一次不在这个前缀中的匹配与下一次匹配就一定不合法了

    同时,当满足这两条必要条件后,其是充分的,构造方案:

    先将第一个1和最后一个-1在最后匹配,由于要求-1在上一次1之后,一定合法

    接下来,由于本来前缀和大于0,现在即非负,那么从小到大枚举左括号去匹配最近的右括号即可(从小到大是为了防止下一次的右括号在这一次之前)

    总结一下,根据$t_{i}$和$v_{i}$可以算出每一个节点的类型,即能否填写这三类中的一种(只要存在可能就可以,至于合法性后面会判),之后可以在0和$L$分别加上若干个1和-1(要求0上至少1个),使得其除去空前缀和整体以外,前缀和严格大于0,且整体和为0

    0和$L$上添加1和-1肯定要尽量少,具体来说就是0上1的个数是$-min(最小的非整体前缀和,0)+1$,$L$上-1的个数是添加上0的1后的整体的和

    如果暴力dp的时间复杂度是$o(n^{2})$的,无法通过

    简单贪心,可以发现如果能取1或-1一定不会填两个(最多会导致0和$L$一个上面多一个,这不劣),且对于自由的,必然是前缀选1,后缀选-1,枚举+前后缀和即可

    (代码大概是有问题的,懒得查了)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 300005
     4 vector<int>v;
     5 int n,L,ans,x[N],t[N],vis[N][2],sum[N][2],mn[N][2];
     6 long long tot;
     7 int main(){
     8     scanf("%d%d",&n,&L);
     9     for(int i=1;i<=n;i++)scanf("%d",&x[i]);
    10     for(int i=1;i<=n;i++)scanf("%d",&t[i]);
    11     for(int i=1;i<=n;i++){
    12         tot+=(t[i]-1)/(2*L);
    13         t[i]=(t[i]-1)%(2*L)+1;
    14         if (2*x[i]>=t[i])vis[i][0]=1;//可以填1 
    15         if (2*(L-x[i])>=t[i])vis[i][1]=1;//可以填-1 
    16         if ((!vis[i][0])&&(!vis[i][1]))tot++;
    17         else{
    18             if (!vis[i][0])v.push_back(1);//必须-1 
    19             if (!vis[i][1])v.push_back(0);//必须1 
    20             if ((vis[i][0])&&(vis[i][1]))v.push_back(2);//任意 
    21         }
    22     }
    23     tot=tot*2+v.size();
    24     for(int i=0;i<v.size();i++){
    25         int p=1;
    26         if (v[i]==1)p=-1;
    27         sum[i+1][0]=sum[i][0]+p;
    28         mn[i+1][0]=min(mn[i][0],sum[i][0]);
    29     }
    30     for(int i=v.size()-1;i>=0;i--){
    31         int p=1;
    32         if (v[i])p=-1;
    33         if (i==v.size()-1)mn[i][1]=0;//强制不为全体的最小前缀和 
    34         else mn[i][1]=min(mn[i+1][1]+p,0);
    35         sum[i][1]=sum[i+1][1]+p;
    36     }
    37     //[0,i),[i,n)
    38     ans=0x3f3f3f3f;
    39     for(int i=0;i<=v.size();i++){
    40         int s0=1-min(mn[i][0],sum[i][0]+mn[i][1]);
    41         int s=sum[i][0]+sum[i][1]+s0;
    42         ans=min(ans,s0+s);
    43     }
    44     printf("%lld",(ans+tot)*L);
    45 }
    View Code
  • 相关阅读:
    常见的文件操作
    Select2
    android 人脸检测你一定会遇到的坑
    react+spring 记录跨域问题的解决方法
    android 解决连接电视机顶盒失败的方法
    java 零基础搭建dubbo运行环境
    android 获取wifi列表,如果你忽略了这个细节,可能你的软件会崩溃
    springMvc+swagger整合例子
    分享一个android静默安装,安装后重新启动app的方法
    分享一个android debug模式,出现 waiting for debugger把界面卡住,取巧的解决办法
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14378126.html
Copyright © 2011-2022 走看看