【bzoj1049】【HAOI2006】【数字序列】

1049: [HAOI2006]数字序列

Time Limit: 10 Sec Memory Limit: 162 MB

Submit: 1117 Solved: 454

[Submit][Status][Discuss]

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。

保证所有数列是随机的。

感觉这道题非常的神啊。

对于第一问还是比较简单的,我们可以由题目知道对于原数列如果是严格上升的,那么a[j]-a[i]>=j-i(j>i)也就是(a[j]-j)-(a[i]-i)>=0

那么我们将所有的a[i]-i,就变成了求a[i]的最长不下降子序列。

第二问就比较难搞了。。

我们继续用上面的a数组。如果对于上面的第一问j可以转移到i,那么就有f[j]+1=f[i]。我们用cost[j,i]表示从j到i这段区间内变成合法的最小费用,那么我们就有了这样一个方程:

g[i]=minf[j]+1=f[i](g[j]+cost[j+1,i])

那么我们怎样去计算cost呢?

这里有一个结论,就是对于j+1到i这段区间来说,肯定有的个点t,使得j+1到t都等于j,t+1到i都等于i。

至于为什么呢,ydc有证明:

然后我们枚举t就好了。

这样是n^3,但是数据比较水。

从网上看的第二问的标解是二分图。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define mid (l+r)/2
#define LL long long
#define inf 210000000
#define INF 2100000000000000000
const int N=36000;
int n,a[N],top=0,stack[N],f[N],tot=0,point[N],next[N],to[N];
LL g[N],sum1[N],sum2[N];
void add(int x,int y)
{
    tot+=1;
    next[tot]=point[x];
    point[x]=tot;
    to[tot]=y;
}
int abs(int x){return x<0?-x:x;}
int main()
{
    int i,j,k,l,r,now;
    scanf("%d",&n);
    for(i=1;i<=n;++i) scanf("%d",&a[i]),a[i]-=i;
    a[++n]=inf;
    stack[0]=-inf;
    for(i=1;i<=n;++i){
        if(a[i]>=stack[top]) stack[++top]=a[i],f[i]=top;
        else{
            l=1;r=top;
            while(l<=r){
                if(a[i]>=stack[mid]) l=mid+1;
                else r=mid-1;
            }
            stack[l]=a[i];
            f[i]=l;
        }
    }
    printf("%d\n",n-top);
    for(i=n;~i;--i){
        g[i]=INF;
        add(f[i],i);
    }
    a[0]=-inf;
    g[0]=0;
    for(i=1;i<=n;++i)
      for(j=point[f[i]-1];j;j=next[j]){
        now=to[j];
        if(now>i) break;
        if(a[now]>a[i]) continue;
        sum1[now-1]=sum2[now-1]=0;
        for(k=now;k<=i;++k){
            sum1[k]=sum1[k-1]+abs(a[now]-a[k]);
            sum2[k]=sum2[k-1]+abs(a[i]-a[k]);
        }
        for(k=now;k<i;++k)
          g[i]=min(g[i],g[now]+sum1[k]-sum1[now]+sum2[i]-sum2[k]);
      }
    printf("%lld\n",g[n]);
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-08 06:20:49

【bzoj1049】【HAOI2006】【数字序列】的相关文章

BZOJ1049 [HAOI2006]数字序列0

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转载请注明出处,侵权必究,保留最终解释权! Description 现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不希望改变的幅度太大. Input 第一行包含一个数n,接下来n个整数按顺序描述每一项的键值.n<=35000

BZOJ1049: [HAOI2006]数字序列

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1049 题解: ydc的题解:http://pan.baidu.com/share/link?uk=2651016602&shareid=1490516411 第二问比较神?考场上敢去猜结论? 代码: 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring&g

【BZOJ 1049】 [HAOI2006]数字序列

1049: [HAOI2006]数字序列 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 979  Solved: 389 [Submit][Status] Description 现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不希望改变的幅度太大. Input 第一行包含一个数n,接下来n个整数按顺序描述每一项的键值. Output 第一行一个整数表示最少需要改变多少

【BZOJ】1049: [HAOI2006]数字序列(lis+特殊的技巧)

http://www.lydsy.com/JudgeOnline/problem.php?id=1049 又是一题神题啊.orz 首先第一个问很容易看出 f[i]=min{f[j]+1, a[i]-a[j]>=i-j} 设b[i]=a[i]-i 得 f[i]=min{f[j]+1, b[i]>=b[j]} 然后就是lis的log算法.... 第二个问,好神!!! 首先发现,如果有b[i]>=b[j]且f[i]==f[j]+1时,区间[j, i]中的点一定都是大于b[i]或者小于b[j],

[HAOI2006]数字序列

题目描述 现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不希望改变的幅度太大. 输入输出格式 输入格式: 第一行包含一个数n,接下来n个整数按顺序描述每一项的键值. 输出格式: 第一行一个整数表示最少需要改变多少个数. 第二行一个整数,表示在改变的数最少的情况下,每个数改变的绝对值之和的最小值. 输入输出样例 输入样例#1: 复制 4 5 2 3 5 输出样例#1: 复制 1 4 说明 [数据范围] 90%的数据n<=

[luogu2501 HAOI2006] 数字序列 (递推LIS)

题目描述 现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不希望改变的幅度太大. 输入输出格式 输入格式: 第一行包含一个数n,接下来n个整数按顺序描述每一项的键值. 输出格式: 第一行一个整数表示最少需要改变多少个数. 第二行一个整数,表示在改变的数最少的情况下,每个数改变的绝对值之和的最小值. 输入输出样例 输入样例#1: 4 5 2 3 5 输出样例#1: 1 4 说明 [数据范围] 90%的数据n<=6000.

[HAOI2006] 数字序列 - dp,二分

现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不希望改变的幅度太大.求在改变的数最少的情况下,每个数改变的绝对值之和的最小值. \(n\leq 35000\),保证数据随机 Solution 第一问很容易,只需要令 \(b_i=a_i-i\),然后跑最长不下降子序列即可 下面考虑第二问,令 \(f[i]\) 表示前 \(i\) 个数构成的数列要变成单调上升需要改动的最小幅度 若 \(a_i,a_j, i<j\) 满足

p2501 [HAOI2006]数字序列

传送门 分析 https://www.luogu.org/blog/FlierKing/solution-p2501 对于第二问的感性理解就是有上下两条线,一些点在上面的线的上面或者下面的线的下面,然后看它们变成哪个线的位置更优 代码 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<ccty

【BZOJ】【1049】【HAOI2006】数字序列

DP 第一问比较水……a[i]-=i 以后就变成最长不下降子序列问题了,第二问这个结论好神奇,考试的时候怎么破?大胆猜想,不用证明?TAT 题解:http://pan.baidu.com/share/link?uk=2651016602&shareid=1490516411 没有将a[0]置为-INF在BZOJ上WA了……so sad…… 1 /************************************************************** 2 Problem: 10