• bzoj 1049 [HAOI2006]数字序列


    【bzoj1049】[HAOI2006]数字序列

    Description

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

    Input

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

    Output

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

    Sample Input

    4
    5 2 3 5

    Sample Output

    1
    4

    HINT

    【数据范围】

    90%的数据n<=6000。

    100%的数据n<=35000。

    保证所有数列是随机的。

    这是证明:

     http://pan.baidu.com/share/link?uk=2651016602&shareid=1490516411

    题解:

        这道题目第一问是十分简单,但是我wrong了好久。

        第二问是变化幅度。

        对于第一问,因为a[i]-a[j]>=i-j

        所以(a[i]-i)-(a[j]-j)>=0

        所以可以设b[i]=a[i]-i

        所以只需要b[i]-b[j]>=0即可

        fz[i]表示当前这个点到i这个点为结尾的最大长度。

        g[i]表示1-i之间的答案。

        g[i]=min g[j]+w[j+1,i],转移条件是fz[j]+1=fz[i]

        有一个结论,在j-i中会有一个t,使得j--t都是b[j],t+1--i都是b[i],

        然后就是暴力即可。

     1 #include<cstring>
     2 #include<cmath>
     3 #include<algorithm>
     4 #include<iostream>
     5 #include<cstdio>
     6 #include<vector>
     7 
     8 #define ll long long
     9 #define N 350007
    10 using namespace std;
    11 inline int read()
    12 {
    13     int x=0,f=1;char ch=getchar();
    14     while(ch>'9'||ch<'0'){if (ch=='-') f=-1;ch=getchar();}
    15     while(ch<='9'&&ch>='0')
    16     {
    17         x=(x<<3)+(x<<1)+ch-'0';
    18         ch=getchar();
    19     }
    20     return x*f;
    21 }
    22 
    23 int n;
    24 ll g[N],s1[N],s2[N];
    25 int a[N],b[N],num,f[N],fz[N];
    26 vector<int>ve[N];
    27 
    28 void mid_find(int x,int i)
    29 {
    30     int l=1,r=num;
    31     while(l<r)
    32     {
    33         int mid=(l+r)>>1;
    34         if (f[mid]<=x) l=mid+1;
    35         else r=mid;
    36     }
    37     if (f[r]<=x) f[++num]=x,fz[i]=num;
    38     else f[r]=x,fz[i]=r;
    39 }
    40 void solve_lis()
    41 {
    42     for (int i=1;i<=n;i++)
    43     {
    44         b[i]=a[i]-i,g[i]=(1LL<<60);
    45         mid_find(b[i],i);
    46         //fz[i]=num;
    47         ve[fz[i]].push_back(i);
    48     }
    49     printf("%d
    ",n-fz[n]);
    50 }
    51 void solve()
    52 {
    53     b[0]=-(1<<30);ve[0].push_back(0);
    54     for (int i=1;i<=n;i++)
    55     {
    56         for (int j=0;j<ve[fz[i]-1].size();j++)
    57         {
    58             int pst=ve[fz[i]-1][j];
    59             if (b[pst]>b[i]) continue;
    60             for (int k=pst;k<=i;k++)
    61                 s1[k]=abs(b[k]-b[pst]),s2[k]=abs(b[k]-b[i]);
    62             for (int k=pst+1;k<=i;k++)
    63                 s1[k]+=s1[k-1],s2[k]+=s2[k-1];
    64             for (int k=pst;k<i;k++)
    65                 g[i]=min(g[i],g[pst]+s1[k]-s1[pst]+s2[i]-s2[k]);        
    66         }
    67     }
    68     printf("%lld",g[n]);
    69 }
    70 int main()
    71 {
    72     n=read();for (int i=1;i<=n;i++) a[i]=read();a[++n]=(1<<30);
    73     solve_lis();
    74     solve();
    75 }
  • 相关阅读:
    2.6map映照容器
    Gym
    开机提示“该站点安全证书的吊销信息不可用,是否继续?”每次开机都询问
    c++中两个类互相引用的问题
    libconfig 读取配置文件
    内存、硬盘等读取速度
    brpc 使用压缩方式传递数据
    查看系统版本
    C++ 编译出现的错误
    2021-02-06 记录大佬的直播内容
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8029781.html
Copyright © 2020-2023  润新知