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

现在我们有一个长度为n的整数序列A。但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列。但是不希望改变过多的数,也不希望改变的幅度太大。求在改变的数最少的情况下,每个数改变的绝对值之和的最小值。

\(n\leq 35000\),保证数据随机

Solution

第一问很容易,只需要令 \(b_i=a_i-i\),然后跑最长不下降子序列即可

下面考虑第二问,令 \(f[i]\) 表示前 \(i\) 个数构成的数列要变成单调上升需要改动的最小幅度

若 \(a_i,a_j, i<j\) 满足 \(a_j-a_i \geq j-i\),则 \([i,j]\) 中一定存在一个 \(k\),使得 \(a[i\dots k]\) 都变成 \(a[i]\),\(a[k+1\dots j]\) 都变成 \(a[j]\),整个序列上升并且花费的代价最小,暴力枚举 \(j,k\) 来转移,时间复杂度为 \(O(n^3)\)

  • 证明可以通过任意构造一种最优解形态,然后通过代价不变的转化使其变化为上述形态

考虑转移到 \(f[i]\) 的决策点 \(j<i\) 要求第一问中的 \(g[j]+1=g[i]\),因此转移点的总数是 \(O(n)\) 到 \(O(n\sqrt n)\) 量级的,且 \(w\) 的区间期望为 \(O(\sqrt n)\),总体复杂度估计为 \(O(n\sqrt n)\) 到 \(O(n^2)\) 之间

在数组前后额外添加最大最小值,可以提供类似于超级源汇的功能

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000005;
int n,a[N],b[N],f[N],g[N],h[N];
vector <int> v[N];
int myabs(int x) {return x>0?x:-x;}
signed main() {
    ios::sync_with_stdio(false);
    cin>>n;
    a[0]=b[0]=-1e9;a[n+1]=b[n+1]=1e9;
    for(int i=1;i<=n;i++) {
        cin>>a[i];
        b[i]=a[i]-i;
    }
    ++n;
    h[1]=b[1]; g[1]=1;
    int len=1;
    for(int i=2;i<=n;i++) {
        int pos=upper_bound(h+1,h+len+1,b[i])-h-1;
        if(pos==len) {
            ++len;
            h[len]=b[i];
            g[i]=len;
        }
        else {
            ++pos;
            h[pos]=b[i];
            g[i]=pos;
        }
    }
    for(int i=1;i<=n;i++) v[g[i]].push_back(i);
    v[0].push_back(0);
    f[0]=0;
    for(int i=1;i<=n;i++) {
        f[i]=1e9;
        for(int j:v[g[i]-1]) if(j<=i&&b[i]>=b[j]) {
            int tmp=0;
            for(int k=j;k<=i;k++) tmp+=myabs(b[i]-b[k]);
            for(int k=j;k<i;k++) {
                tmp-=myabs(b[i]-b[k]);
                tmp+=myabs(b[j]-b[k]);
                f[i]=min(f[i],tmp+f[j]);
            }
        }
    }
    cout<<n-len<<endl<<f[n]<<endl;
}

原文地址:https://www.cnblogs.com/mollnn/p/12384566.html

时间: 2024-11-10 07:11:44

[HAOI2006] 数字序列 - dp,二分的相关文章

【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 第一行一个整数表示最少需要改变多少

BZOJ1049 [HAOI2006]数字序列0

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

CODEVS3037 线段覆盖 5[序列DP 二分]

3037 线段覆盖 5  时间限制: 3 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description 数轴上有n条线段,线段的两端都是整数坐标,坐标范围在0~10^18,每条线段有一个价值,请从n条线段中挑出若干条线段,使得这些线段两两不覆盖(端点可以重合)且线段价值之和最大. 输入描述 Input Description 第一行一个整数n,表示有多少条线段. 接下来n行每行三个整数, ai bi ci,分别代表第i条线段的左端点ai,右端点b

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

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

【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<=

p2501 [HAOI2006]数字序列

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

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】数字序列

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