zoukankan      html  css  js  c++  java
  • [dp][瞎搞] 洛谷 P2501 数字序列

    题目描述

    现在我们有一个长度为n的整数序列A。但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列。但是不希望改变过多的数,也不希望改变的幅度太大。

    输入输出格式

    输入格式:

    第一行包含一个数n,接下来n个整数按顺序描述每一项的键值。

    输出格式:

    第一行一个整数表示最少需要改变多少个数。

    第二行一个整数,表示在改变的数最少的情况下,每个数改变的绝对值之和的最小值。

    输入输出样例

    输入样例#1:
    4
    5 2 3 5
    输出样例#1:
    1
    4

    说明

    【数据范围】

    90%的数据n<=6000。

    100%的数据n<=35000。

    保证所有数列是随机的。

    题解

    • 我们可以把序列中的每个数减去他们的位置构成一个新的序列,a[i]-=i
    • 对于第一问,我们可以求最多有多少个点不用修改,就是最长不下降子序列,答案就是n-最长不下降子序列的长度
    • 对于第二问,就是求把这个序列转换成最长不下降子序列的最小代价
    • 证明对于[i,j]的一段区间并且满足f[i]+1=f[j]和a[i]<=a[j]
    • 我们把它变成不下降的最小代价一定是从中间取一个点t,我们把[i+1,t]全都变成a[i],[t+1,j-1]全都变成a[j]
    • 大爷的证明如下:
    • 这样我们枚举t就好了,因为随机数据嘛,应该可以过的

    代码

     1 #include <cstdio>
     2 #include <cmath>
     3 #include <iostream>
     4 using namespace std;
     5 #define inf 210000000
     6 const int N=35010;
     7 int n,cnt,top,a[N],Q[N],f[N],head[N];
     8 long long g[N],x[N],y[N];
     9 struct edge {int to,from;}e[N];
    10 void insert(int x,int y) { e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt; }
    11 int main()
    12 {
    13     scanf("%d",&n);
    14     for (int i=1;i<=n;i++) scanf("%d",&a[i]),a[i]-=i;
    15     a[++n]=inf,Q[0]=-inf;
    16     for (int i=1;i<=n;i++)
    17         if (a[i]>=Q[top]) Q[++top]=a[i],f[i]=top;
    18         else 
    19         {
    20             int l=1,r=top;
    21             while (l<=r)
    22             {
    23                 int mid=l+r>>1;
    24                 if (a[i]>=Q[mid]) l=mid+1; else r=mid-1;
    25             }
    26             Q[l]=a[i],f[i]=l;
    27         }
    28     printf("%d
    ",n-top);
    29     for (int i=n;~i;i--) g[i]=inf*1e5,insert(f[i],i);
    30     a[0]=-inf,g[0]=0;
    31     for (int i=1;i<=n;i++)
    32         for (int j=head[f[i]-1];j;j=e[j].from)
    33         {
    34             if (e[j].to>i) break;
    35             if (a[e[j].to]>a[i]) continue;
    36             x[e[j].to-1]=y[e[j].to-1]=0;
    37             for (int k=e[j].to;k<=i;k++) x[k]=x[k-1]+abs(a[e[j].to]-a[k]),y[k]=y[k-1]+abs(a[i]-a[k]);
    38             for (int k=e[j].to;k<i;k++) g[i]=min(g[i],g[e[j].to]+x[k]-x[e[j].to]+y[i]-y[k]);
    39         }
    40     printf("%lld",g[n]);
    41 }
  • 相关阅读:
    SpringBoot 整合Shiro
    Shiro 学习
    SpringBoot 整合security、thymeleaf
    【SpringBoot__Mybatis】整合MyBatis 配置文件版2
    SpringBoot 配置Druid数据源及监控
    lombok 使用
    thymeleaf 常用
    随机模块
    md5加密
    python正则
  • 原文地址:https://www.cnblogs.com/Comfortable/p/10413535.html
Copyright © 2011-2022 走看看