zoukankan      html  css  js  c++  java
  • CF1295E Permutation Separation

    线段树

    难得把E想出来,写出来,但却没有调出来(再给我5分钟),我的紫名啊,我一场上紫的大好机会啊


    首先考虑是否能将$k$在$1$--$n-1$的每一个的最小代价都求出来

    因为$k$从$i$到$i-1$左右两边的集合只相差一个数,所以可以考虑递推

    可以发现如果最终满足条件,那么左边集合的最大数一定为该集合当前的大小

    且在每一个小于此大小的数都存在于左边这个集合中

    由于给出的序列是一个排列,每一个数的范围是$1$--$n$

    那么只要对于每一个k都进行枚举左边集合的大小计算代价,取最小值,就是该取该k时最小值

    但直接暴力枚举的复杂度时$O(n^{2})$的

    那么可以线段树维护以左边集合大小为每一个元素的序列

    我们让$k$从$n-1$到$1$开始考虑递推

    对于将$k$减一,左边集合只差了一个数

    设这个数为$p$,代价为$v$

    那么这个数对枚举左边集合大小的影响即是

    集合大小为$p$-$n$的代价$+v$

    集合大小为$0$-$p-1$的代价$-v$

    然后线段树维护区间修改即可

     1 #include <bits/stdc++.h>
     2 #define m_k make_pair
     3 #define int long long
     4 #define inf (int)1e18
     5 using namespace std;
     6 const int N=2*1e5+100;
     7 int n,p[N],v[N],sum[N],ans;
     8 struct node
     9 {
    10     int MIN,lazy;
    11 }sh[N*4];
    12 void pushup(int x)
    13 {
    14     sh[x].MIN=min(sh[x+x].MIN,sh[x+x+1].MIN);
    15 }
    16 void pushdown(int x)
    17 {
    18     int v=sh[x].lazy;
    19     sh[x+x].lazy+=v;
    20     sh[x+x].MIN+=v;
    21     sh[x+x+1].lazy+=v;
    22     sh[x+x+1].MIN+=v;
    23     sh[x].lazy=0;
    24 }
    25 void build(int x,int l,int r)
    26 {
    27     if (l==r)
    28     {
    29         sh[x].lazy=0;
    30         sh[x].MIN=sum[n]-sum[l];//此时将k取到n,所有元素都在左边集合
    31         return;
    32     }
    33     int mid=(l+r)>>1;
    34     build(x+x,l,mid);
    35     build(x+x+1,mid+1,r);
    36     pushup(x);
    37 }
    38 void change(int x,int l,int r,int L,int R,int v)//线段树维护区间修改
    39 {
    40     if (L<=l && R>=r)
    41     {
    42         sh[x].MIN+=v;
    43         sh[x].lazy+=v;
    44         return;
    45     }
    46     pushdown(x);
    47     int mid=(l+r)>>1;
    48     if (L<=mid) change(x+x,l,mid,L,R,v);
    49     if (R>mid) change(x+x+1,mid+1,r,L,R,v);
    50     pushup(x);
    51 }
    52 signed main()
    53 {
    54     scanf("%lld",&n);
    55     for (int i=1;i<=n;i++)
    56       scanf("%lld",&p[i]);
    57     for (int i=1;i<=n;i++)
    58     {
    59         int a;
    60         scanf("%lld",&a);
    61         v[p[i]]=a;//记录每一个数值的代价
    62     }
    63     for (int i=1;i<=n;i++) sum[i]=sum[i-1]+v[i];//计算前缀和
    64     build(1,0,n);
    65     ans=inf;//由于k不能取到n,所有ans不进行计算,直接赋值为inf
    66     for (int i=n;i>=2;i--)
    67     {
    68         change(1,0,n,p[i],n,v[p[i]]);//同上
    69         change(1,0,n,0,p[i]-1,-v[p[i]]);
    70         ans=min(ans,sh[1].MIN);
    71     }
    72     printf("%lld
    ",ans);
    73 }
    View Code
  • 相关阅读:
    【郑轻邀请赛 G】密室逃脱
    【郑轻邀请赛 C】DOBRI
    【郑轻邀请赛 F】 Tmk吃汤饭
    【郑轻邀请赛 I】这里是天堂!
    【郑轻邀请赛 B】base64解密
    【郑轻邀请赛 A】tmk射气球
    【郑轻邀请赛 H】 维克兹的进制转换
    解决adb command not found以及sdk环境配置
    adb shell 命令详解,android, adb logcat
    Unexpected exception 'Cannot run program ... error=2, No such file or directory' ... adb'
  • 原文地址:https://www.cnblogs.com/huangchenyan/p/12244765.html
Copyright © 2011-2022 走看看