• [HAOI2006] 数字序列


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

    (nleq 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[idots k]) 都变成 (a[i])(a[k+1dots j]) 都变成 (a[j]),整个序列上升并且花费的代价最小,暴力枚举 (j,k) 来转移,时间复杂度为 (O(n^3))

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

    考虑转移到 (f[i]) 的决策点 (j<i) 要求第一问中的 (g[j]+1=g[i]),因此转移点的总数是 (O(n))(O(nsqrt n)) 量级的,且 (w) 的区间期望为 (O(sqrt n)),总体复杂度估计为 (O(nsqrt 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;
    }
    
    
  • 相关阅读:
    随笔导航
    利用CORDIC算法计算三角函数
    粒子群算法求一元函数最值问题
    基于粒子群算法的分组背包MATLAB实现
    遇到过的MATLAB函数小总结
    FFT原理及C++与MATLAB混合编程详细介绍
    DPSK通信系统的FPGA实现
    矩阵QR分解的MATLAB与C++实现
    矩阵LU分解的MATLAB与C++实现
    两种频率调制(FM)方法的MATLAB实现
  • 原文地址:https://www.cnblogs.com/mollnn/p/12384566.html
Copyright © 2020-2023  润新知