zoukankan      html  css  js  c++  java
  • [HAOI2006]数字序列

    题目描述

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

    输入输出格式

    输入格式:

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

    输出格式:

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

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

    输入输出样例

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

    说明

    【数据范围】

    90%的数据n<=6000。

    100%的数据n<=35000。

    保证所有数列是随机的。

    一份讲解的链接

    先将数组每一位a[i]减i

    这样单调上升就变成了不下降

    在给第n+1位加一个正无穷的值(可以做所有子串的结尾,用于统计第2问的答案)

    第一问:求最长不下降串长L

    答案就是n-L

    第二问:首先令f[i]表示1~i的最长不下降长度,g[i]为将1~i变为不下降的代价

    对于一对(i,j)且f[i]=f[j]+1

    设w(i,j)为将j+1~i变为单调不下降的最小代价

    有一个结论:

    找到一个断点k

    j+1~k全部变成a[j],k+1~i全部变成a[i]

    这样一定可以找到这个最小代价

    证明见链接

    这个复杂度很玄学,最坏O(n^3),但数据是随机的,所以远远达不到

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 using namespace std;
     7 typedef long long lol;
     8 struct Node
     9 {
    10   int next,to;
    11 }edge[100001];
    12 int L,n,head[40001],num,Min[40001],a[40001];
    13 lol s1[40001],s2[40001],g[40001],f[40001];
    14 void add(int u,int v)
    15 {
    16   num++;
    17   edge[num].next=head[u];
    18   head[u]=num;
    19   edge[num].to=v;
    20 }
    21 int find(int x)
    22 {
    23   int l=0,r=L,as=0;
    24   while (l<=r)
    25     {
    26       int mid=(l+r)/2;
    27       if (Min[mid]<=x) as=mid,l=mid+1;
    28       else r=mid-1;
    29     }
    30   return as;
    31 }
    32 int main()
    33 {int i,j,k;
    34   cin>>n;
    35   for (i=1;i<=n;i++)
    36     {
    37       scanf("%d",&a[i]);
    38       a[i]-=i;
    39     }
    40   ++n;
    41   a[n]=(1<<30);
    42   memset(Min,127,sizeof(Min));
    43   Min[0]=-1<<30;L=0;
    44   for (i=1;i<=n;i++)
    45     {
    46       int t=find(a[i]);
    47       f[i]=t+1;
    48       L=max(L,t+1);
    49       Min[t+1]=min(Min[t+1],a[i]);
    50     }
    51   cout<<n-L<<endl;
    52   for (i=n;i>=0;i--)
    53     {
    54       add(f[i],i);
    55       g[i]=1ll<<60;
    56     }
    57   a[0]=-1<<30;g[0]=0;
    58   for (i=1;i<=n;i++)
    59     {
    60       for (j=head[f[i]-1];j;j=edge[j].next)
    61     {
    62       int v=edge[j].to;
    63       if (v>i) break;
    64       if (a[v]>a[i]) continue;
    65       for (k=v;k<=i;k++)
    66         s1[k]=abs(a[k]-a[v]),s2[k]=abs(a[k]-a[i]);
    67       for (k=v+1;k<=i;k++)
    68         s1[k]+=s1[k-1],s2[k]+=s2[k-1];
    69       for (k=v;k<i;k++)
    70         g[i]=min(g[i],g[v]+s1[k]-s1[v]+s2[i]-s2[k]);
    71     }
    72     }
    73   cout<<g[n];
    74 }
  • 相关阅读:
    CSS绿色导航代码
    一款简单另类的CSS导航菜单代码
    来自腾讯QQ网站首页的选项卡菜单代码
    JavaScript学习笔记之应用技巧二
    JavaScript学习笔记之创建字符串比较
    Delegate学习笔记
    ADO.NET Entity FrameWork学习笔记
    Reflector学习之特性理解
    字符串范围截取(转载)
    Delegate学习笔记之事件订阅
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8485692.html
Copyright © 2011-2022 走看看