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
  • 相关阅读:
    BZOJ 3514 Codechef MARCH14 GERALD07加强版
    WT
    Codeforces 348
    POI 2010
    Codeforces 336
    MVC实例及用三层架构实现对学生信息的增删改查
    欠拟合和过拟合
    线性回归案例
    梯度下降法介绍
    线性回归的损失函数和梯度下降
  • 原文地址:https://www.cnblogs.com/huangchenyan/p/12244765.html
Copyright © 2011-2022 走看看