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

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

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

输入输出样例

输入样例#1:

4

5 2 3 5

输出样例#1:

1

4

说明

【数据范围】

90%的数据n<=6000。

100%的数据n<=35000。

保证所有数列是随机的。

题解

只会做第一问 比较简单求[a[i]-i]最长不降

第二问 膜拜题解

code:

//By Menteur_Hxy
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define M(a,b) memset(a,(b),sizeof(a))
#define F(i,a,b) for(register int i=(a);i<=(b);i++)
#define C(i,a,b) for(register int i=(b);i>=(a);i--)
#define E(i,u) for(register int i=head[u];i;i=nex[i])
using namespace std;

inline LL rd() {
    LL x=0,fla=1; char c=‘ ‘;
    while(c>‘9‘|| c<‘0‘) {if(c==‘-‘) fla=-fla; c=getchar();}
    while(c<=‘9‘ && c>=‘0‘) x=x*10+c-‘0‘,c=getchar();
    return x*fla;
}

inline void out(LL x){
    int a[30],wei=0;
    if(x<0) putchar(‘-‘),x=-x;
    for(;x;x/=10) a[++wei]=x%10;
    if(wei==0){ puts("0"); return;}
    for(int j=wei;j>=1;--j) putchar(‘0‘+a[j]);
    putchar(‘\n‘);
}

const int N=35010;
const int INF=0x3f3f3f3f;
int n,tp,cnt,L;
int b[N],f[N],head[N],to[N],nex[N],mn[N];
LL g[N],s1[N],s2[N];

void add(int x,int y) {
    nex[++cnt]=head[x],to[cnt]=y,head[x]=cnt;
}

int find(int x) { int l=1,r=L,t=0;
    while(l<=r) { int mid=(l+r)>>1;
        if(mn[mid]<=x) t=mid,l=mid+1;
        else r=mid-1;
    }
    return t;
}

void dp() {
    M(mn,127);
    mn[0]=-INF;
    F(i,1,n) { int t=find(b[i]);
        f[i]=t+1;
        L=max(L,t+1);
        mn[t+1]=min(mn[t+1],b[i]);
    }
}

int main() {
    n=rd();
    F(i,1,n) b[i]=rd()-i; b[++n]=INF;
    dp();
    C(i,0,n) add(f[i],i),g[i]=(LL)INF;
    g[0]=0;b[0]=-INF;
    F(x,1,n) E(i,f[x]-1) { int p=to[i];
        if(p>x) break;
        if(b[p]>b[x]) continue;
        F(j,p,x) s1[j]=abs(b[p]-b[j]),s2[j]=abs(b[x]-b[j]);
        F(j,p+1,x) s1[j]+=s1[j-1],s2[j]+=s2[j-1];
        F(j,p,x-1) g[x]=min(g[x],g[p]+s1[j]-s1[p]+s2[x]-s2[j]);
    }
    out(n-f[n]);out(g[n]);
    return 0;
}  

原文地址:https://www.cnblogs.com/Menteur-Hxy/p/9159734.html

时间: 2024-10-10 09:13:12

[luogu2501 HAOI2006] 数字序列 (递推LIS)的相关文章

【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],

BZOJ1049 [HAOI2006]数字序列0

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

[HAOI2006]数字序列

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

序列递推——cf1204E

/* 显然用dp[i][j]来表示i个1,j个-1的结果 dp[i][j]由dp[i-1][j]和dp[i][j-1]转移而来 即dp[i][j]对应的所有序列,都可以由dp[i-1][j]在前面加一个1或dp[i][j-1]在前面加一个-1得到, 这里加在前面是因为更容易统计 考虑1加在前面,那么对于任意一种(i-1,j)的排列,贡献都+1,C(i-1+j,j) 考虑-1加在前面,那么对于某些(i,j-1)的排列,贡献-1 考虑哪些不需要,前缀中-1的个数始终大于1的序列本来答案就是0,因此不

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

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

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

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