zoukankan      html  css  js  c++  java
  • BZOJ1049:[HAOI2006]数字序列(DP)

    Description

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

    Input

      第一行包含一个数n,接下来n个整数按顺序描述每一项的键值。n<=35000,保证所有数列是随机的

    Output

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

    Sample Input

    4
    5 2 3 5

    Sample Output

    1
    4

    Solution

    膜拜非凡学长

    Code

     1 #include<iostream>
     2 #include<cstdlib>
     3 #include<cstdio>
     4 #define N (35009)
     5 #define LL long long
     6 using namespace std;
     7 
     8 struct Edge{int to,next;}edge[N];
     9 int n,top,stack[N],f[N],a[N];
    10 LL g[N],s1[N],s2[N];
    11 int head[N],num_edge;
    12 
    13 void add(int u,int v)
    14 {
    15     edge[++num_edge].to=v;
    16     edge[num_edge].next=head[u];
    17     head[u]=num_edge;
    18 }
    19 
    20 void Solve1()
    21 {
    22     a[++n]=2e9; stack[0]=-2e9;
    23     for (int i=1; i<=n; ++i)
    24         if (a[i]>=stack[top]) stack[++top]=a[i],f[i]=top;
    25         else
    26         {
    27             int l=1,r=top,ans=-1;
    28             while (l<=r)
    29             {
    30                 int mid=(l+r)>>1;
    31                 if (stack[mid]<=a[i]) l=mid+1;
    32                 else ans=mid,r=mid-1;
    33             }
    34             stack[ans]=a[i]; f[i]=ans;
    35         }
    36     printf("%d
    ",n-top);
    37 }
    38 
    39 void Solve2()
    40 {
    41     for (int i=n; i>=0; --i)
    42         g[i]=2e18,add(f[i],i);
    43     a[0]=-2e9; g[0]=0;
    44     for (int i=1; i<=n; ++i)
    45         for (int j=head[f[i]-1]; j; j=edge[j].next)
    46         {
    47             int pre=edge[j].to;
    48             if (pre>i) break;
    49             if (a[pre]>a[i]) continue;
    50             s1[pre-1]=s2[pre-1]=0;
    51             for (int k=pre; k<=i; ++k)
    52             {
    53                 s1[k]=s1[k-1]+abs(a[k]-a[pre]);
    54                 s2[k]=s2[k-1]+abs(a[k]-a[i]);
    55             }
    56             for (int k=pre; k<i; ++k)
    57                 g[i]=min(g[i],g[pre]+s1[k]-s1[pre]+s2[i]-s2[k]);
    58         }
    59     printf("%lld
    ",g[n]);
    60 }
    61 
    62 int main()
    63 {
    64     scanf("%d",&n);
    65     for (int i=1; i<=n; ++i)
    66         scanf("%d",&a[i]),a[i]-=i;
    67     Solve1(); Solve2();
    68 }
  • 相关阅读:
    poj 2155 B
    hdu 1556 A
    hdu 1556 A
    #366 A-C
    最长上升子序列
    Codeforces Div3 #501 A-E(2) F以后补
    字典的建立 查找
    字典序大小
    头文件模板
    01背包模板 及 优化
  • 原文地址:https://www.cnblogs.com/refun/p/9799030.html
Copyright © 2011-2022 走看看