zoukankan      html  css  js  c++  java
  • 【BZOJ1049】[HAOI2006]数字序列

    【BZOJ1049】[HAOI2006]数字序列

    题面

    bzoj

    洛谷

    题解

    第一问

    直接做不是很好做,可以转化为最大化不修改的点最多

    对于原数列,对于(i,j)((i<j)),使得(i,j)不被修改的必要条件是(A_j-A_igeq j-i)

    于是可以写出一个(dp)方程:(dp_i=max_{j=0}^{i-1};dp_j+1(A_j-A_igeq j-i))

    将不等式(A_j-A_igeq j-i)变为(A_j-jgeq A_i-i),可以看出第一问就是求数列(B_i=A_i-i)的最长不降子序列的长度,再用(n)减去即可

    第二问

    要求你在第一问的情况下要求变化幅度最小。

    在第一问的情况下对于每个有(dp_j=dp_i+1)(i,j)((i<j)),肯定是变化(i,j)中间的数

    怎么变?

    有一个结论:

    对于(i,j)中间的位置(k),必有(i)~(k)全变为(A_i)(k+1)~(j)全变为(A_j)

    因为很(bu)显(hui)然(zheng)就不证了。。。

    那么我们设(g_i)表示排好(1)~(i)的最小代价

    (g_j=min_{i=0}^{j-1}g_i+w(i,j)(dp_j=dp_i+1))((w(i,j))表示修改区间([i,j])的贡献)

    复杂度(O(能过))

    代码

    #include <iostream> 
    #include <cstdio> 
    #include <cstdlib> 
    #include <cstring> 
    #include <cmath> 
    #include <algorithm>
    #include <vector> 
    using namespace std; 
    #define int long long 
    inline int gi() { 
        register int data = 0, w = 1; 
        register char ch = 0; 
        while (!isdigit(ch) && ch != '-') ch = getchar(); 
        if (ch == '-') w = -1, ch = getchar(); 
        while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar(); 
        return w * data; 
    }
    const int MAX_N = 35005;
    const int INF = 1e13; 
    int N, a[MAX_N], b[MAX_N], c[MAX_N]; 
    int f[MAX_N], g[MAX_N], s1[MAX_N], s2[MAX_N]; 
    vector<int> vec[MAX_N]; 
    signed main () { 
        N = gi(); for (int i = 1; i <= N; i++) a[i] = gi(), b[i] = a[i] - i; 
        fill(&f[1], &f[N + 1], INF); 
        for (int i = 1; i <= N; i++) c[i] = upper_bound(&f[1], &f[N + 1], b[i]) - f , f[c[i]] = b[i]; 
        printf("%lld
    ", N - (long long)(lower_bound(&f[1], &f[N + 1], INF) - f - 1)); 
        N++; c[N] = lower_bound(&f[1], &f[N + 1], INF) - f; b[N] = INF; 
        fill(&g[1], &g[N + 1], INF); 
        b[0] = -INF; 
        for (int i = 0; i <= N; i++) vec[c[i]].push_back(i); 
        for (int i = 1; i <= N; i++) { 
            vector<int> :: iterator ite; int prv = c[i] - 1; 
            for (ite = vec[prv].begin(); ite != vec[prv].end(); ++ite) {
                int k = *ite; 
                if (k > i) break; if (b[k] > b[i]) continue; 
                s1[k - 1] = s2[k - 1] = 0; 
                for (int j = k; j <= i; j++) s1[j] = s1[j - 1] + abs(b[k] - b[j]); 
                for (int j = k; j <= i; j++) s2[j] = s2[j - 1] + abs(b[i] - b[j]); 
                for (int j = k; j <= i; j++) g[i] = min(g[i], g[k] + s1[j] - s1[k - 1] + s2[i] - s2[j]); 
            } 
        } 
        printf("%lld
    ", g[N]); 
        return 0; 
    } 
    
  • 相关阅读:
    Mysql_常规操作
    三剑客
    Nginx_安全2
    shell_常规小脚本
    redis数据库持久化
    redis数据库操作
    keepalived高可用lvs集群
    ansible的roles角色
    keepalived高可用
    keepalived概念
  • 原文地址:https://www.cnblogs.com/heyujun/p/10179012.html
Copyright © 2011-2022 走看看