zoukankan      html  css  js  c++  java
  • [atAGC045B]01 Unbalanced

    将0变为-1后求前缀和,那么$s$的价值即为最大的前缀和-最小的前缀和(特别的,空前缀的前缀和为0)

    令$f(x)$表示当最大的前缀和不大于$x$时,最小的前缀和最大是多少,答案即为$min_{x}x-f(x)$

    考虑如何求$f(x)$,可以贪心,先令所有位置都为-1,记最大的前缀和为$k$(要有$kle x$),然后从前往后贪心将每一个-1变为1并判断是否仍然有$kle x$,通过维护后缀最大值可以做到$o(n)$

    关于贪心正确性的证明:考虑构造,将非最优解第一个与最优解不同的位置改成最优解的位置

    (这里的位置指修改的位置,即-1变成1的位置所构成的集合)

    较优解相当于对这两个位置之间全部加2,那么$f(x)$必然更大,同时对于这段区间之前的操作较优解和最优解相同(但最优解在这段区间中可能还有修改),最优解合法,较优解一定也合法

    (最优解指通过贪心所得到的解,较优解指由非最优解构造得到的解)

    进一步的,考虑$x$和$x-2$,若后者仍有位置填的是-1,那么前者一定是通过后者将第一个-1的位置改成1得到(联系贪心的过程,这里可以改成1,且之后与$x-2$相同)

    对于$f(x)$和$f(x-2)$,前者即为将后者的一个后缀增加2,即有$f(x)le f(x-2)+2$,简单的变形可以得到$(x-2)-f(x-2)le x-f(x)$

    设$k$为所有位置都填-1时的最大前缀和,即仅需要计算$f(k)$和$f(k+1)$,复杂度降为$o(n)$

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 1000005
     4 int n,sum[N],mx[N];
     5 char s[N];
     6 int calc(int k){
     7     int tag=0,ans=0;
     8     for(int i=0;i<n;i++){
     9         if ((s[i]=='?')&&(2*(tag+1)+mx[i+1]<=k))tag++;
    10         ans=min(ans,2*tag+sum[i+1]);
    11     }
    12     return ans;
    13 }
    14 int main(){
    15     scanf("%s",s);
    16     n=strlen(s);
    17     for(int i=0;i<n;i++)
    18         if (s[i]=='1')sum[i+1]=sum[i]+1;
    19         else sum[i+1]=sum[i]-1;
    20     mx[n]=sum[n];
    21     for(int i=n;i;i--)mx[i-1]=max(sum[i-1],mx[i]);
    22     printf("%d",min(mx[0]-calc(mx[0]),mx[0]+1-calc(mx[0]+1)));
    23 } 
    View Code
  • 相关阅读:
    SharePoint 2010 与RMS集成方案
    VBS基础教程
    c#中csc命令的用法
    文本文件编码格式转换
    “本地连接”属性中“身份验证”选项卡消失的处理方法
    如何组建中小型SharePoint服务器场
    PHP文件上传详解
    Flash AS3 RadioButton的使用方法
    SUSE ssh登录慢解决办法,ssh登录失败,但是strace一下就好了的分析查询 第一次ssh,路由的问题
    AS3组件之ComboBox下拉框
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14168277.html
Copyright © 2011-2022 走看看