POJ3666-Making the Grade(左偏树 or DP)

左偏树

炒鸡棒的论文《左偏树的特点及其应用

虽然题目要求比论文多了一个条件,但是……只需要求非递减就可以AC……数据好弱……

虽然还没想明白为什么,但是应该觉得应该是这样——求非递减用大顶堆,非递增小顶堆……

这题和bzoj1367题意差不多,但是那题求的是严格递增。(bzoj找不到那道题,可能是VIP或什么原因?

严格递增的方法就是每一个数字a[i]都要减去i,这样求得的b[i]也要再加i,保证了严格递增(为什么对我就不知道了

代码比较水,因为题目数据的问题,我的代码也就钻了空子,反正ac就好了。。。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 2005;
typedef long long ll;

struct LTree {
    int l, r, sz;
    int key, dis;
    bool operator<(const LTree lt) const {
        return key < lt.key;
    }
} tr[N];
int cnt_tr;

int NewTree(int k) {
    tr[++cnt_tr].key = k;
    tr[cnt_tr].l = tr[cnt_tr].r = tr[cnt_tr].dis = 0;
    tr[cnt_tr].sz = 1;
    return cnt_tr;
}

int Merge(int x, int y) {
    if (!x || !y) return x + y;
    if (tr[x] < tr[y]) swap(x, y);
    tr[x].r = Merge(tr[x].r, y);
    if (tr[tr[x].l].dis < tr[tr[x].r].dis) swap(tr[x].l, tr[x].r);
    tr[x].dis = tr[tr[x].r].dis + 1;
    tr[x].sz = tr[tr[x].l].sz + tr[tr[x].r].sz + 1;
    return x;
}

int Top(int x) {
    return tr[x].key;
}

void Pop(int &x) {
    x = Merge(tr[x].l, tr[x].r);
}

int a[N], root[N], num[N];

int main() {
    int n;
    while (~scanf("%d",&n)) {
        ll sum, tmp, ans;
        cnt_tr = sum = tmp = 0;
        for (int i = 0; i < n; ++i) {
            scanf("%d", a+i);
            sum += a[i];
        }
        int cnt = 0;
        for (int i = 0; i < n; ++i) {
            root[++cnt] = NewTree(a[i]);
            num[cnt] = 1;
            while (cnt > 1 && Top(root[cnt]) < Top(root[cnt-1])) {
                cnt--;
                root[cnt] = Merge(root[cnt], root[cnt+1]);
                num[cnt] += num[cnt+1];
                while (tr[root[cnt]].sz*2 > num[cnt]+1) Pop(root[cnt]);
            }
        }
        int px = 0;
        for (int i = 1; i <= cnt; ++i)
            for (int j = 0, x = Top(root[i]); j < num[i]; ++j)
                tmp += abs(a[px++]-x);
        ans = tmp;

        printf("%lld\n", ans);
    }
    return 0;
}

 

这题DP也很神奇,挖坑,明天学……

----

考虑dp,dp[i][j]表示前i个数,最后一个数是j的最小花费

dp方程:dp[i][j]=min(dp[i-1][k], k≤j) + abs(a[i]-j)

j的范围1e9,是因为对于每一个i来说,当最优解的时候j一定是a数列中的数,所以只需枚举a数列中的值就可以了。

容易想到dp[i-1][k]就不需要另外一层循环就了,同时可以使用滚动数组(不使用明显也够

上面求的是不减,求不增把数组到倒过来就可以了。(懒,没写。。

时间复杂度O(n^2),比上面左偏树明显慢了不少。

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 2005;
const int INF = 0x5f5f5f5f;

int dp[N][N];
int a[N], b[N];
int main() {
    //freopen("in", "r", stdin);
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", a+i);
        b[i] = a[i];
    }
    sort(b+1, b+1+n);
    int last;
    for (int i = 1; i <= n; ++i) {
        last = INF;
        for (int j = 1; j <= n; ++j) {
            last = min(last, dp[i-1][j]);
            dp[i][j] = fabs(b[j]-a[i]) + last;
        }
    }
    int ans = INF;
    for (int i = 1; i <= n; ++i) {
        ans = min(ans, dp[n][i]);
    }

    printf("%d\n", ans);

    return 0;
}

 

  

相关推荐:

DP-最长公共子序列

思路:dp[i][j]的含义为str1[0..i]与str2[0..j]的最长公共子序列长度. #include<iostream> #include<string> usingnamespacestd; constintmaxn=100; intmain() { strin...

DP最长公共子序列的代码示例

这篇文章主要为大家详细介绍了DP最长公共子序列的实现,文中示例代码介绍的非常详细,零基础也能参考此文章,感兴趣的小伙伴们可以参考一下。思路:dp[i][j]的含义为str1[0..i]与str2[0..j]的最长公共子序列长度.#include<iostream> #include&lt...

java DP背包使用示例

思路:dp[i][j]表示的是前i个物品背包所能容纳不超过bagw的最大价值.#include<iostream> usingnamespacestd; constintmaxn=100; intmain() {   intn,bagw;   in...

从最简单的线性DP开始

导读^_^ 线性DP可以说是最常见的DP问题。 从本期开始,我们将从最简单的线性DP开始学起。 后面同时更新一些经典的面试题带大家更加深入的学习线性DP 如何计算动态规划的时间复杂度? 状态数x转移次数 理解线性 按照某种线性关系进行线性的状态的转移。 数字三角形 思路 我们先对矩阵结构进行研究 推...

Atcoder dp I Coins 题解

Atcoder链接:Coins Luogu链接:Coins $\scr{\color{BlueViolet}{Solution}}$ 观察数据,发现$\cal{n}\le3000$,说明$Ο(\cal{n^2})$可过,容易想到DP。 用$\cal{dp[i][j]}$表示抛完第$\cal{i}$个...

【转】【DP_树形DP专辑】【9月9最新更新】【from zeroclock's blog】

树,一种十分优美的数据结构,因为它本身就具有的递归性,所以它和子树见能相互传递很多信息,还因为它作为被限制的图在上面可进行的操作更多,所以各种用于不同地方的树都出现了,二叉树、三叉树、静态搜索树、AVL树,线段树、SPLAY树,后缀树等等.. 枚举那么多种数据结构只是想说树方面的内容相当多,本专辑只...

CF dp 题(1500-2000难度)

前言 从后往前刷 update新增\(\text{\color{red}{Mark}}\)标记功能,有一定难度的题标记为\(\text{\color{red}{红}}\)色。 题单(刷过的题就会登记在上面) 2BTheleastroundway只有\(2^a*5^b\)尾随'\(0\)'的个数为\(...

CodeForces 109C 树形DP Lucky Tree

赶脚官方题解写得挺清楚的说,=_= 注意数据范围用longlong,否则会溢出。 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include&lt...