hdu4362 dp + 单调队列优化

dp传输方程很easy需要 dp[i][j] = min{dp[i - 1][k] + abs(pos[i][j] -pos[i - 1][j]) + cost[i][j]}

n行m一排 每个传输扫描m二级 干脆n*m*m 至O(10^7)    1500ms,能够暴力一试。姿势不正确就会TLE

事实上加上个内联函数求绝对值,同一时候赋值时候不使用min(a, b)  用G++交 就能够水过

正解是:由于每一个转移都是从上一层全部的状态開始转移。将上一层的状态依据pos排序

对当前状态的pos进行讨论,其坐标轴左边的点dp[i][j] = dp[i - 1][k] - pos][i - 1][k]+ pos[i][j]  + cost[i][j]

对其坐标轴右边的点便是 dp[i][j] = dp[i - 1][k]+ pos][i - 1][k]  - pos[i][j] + cost[i][j]。       pos][i][j]
和 cost[i][j]是常数。

维护一个lans[i],表示上一层0 ~ i位置的dp[i - 1][k] - pos][i - 1][k]最小值。   和一个rans[i],表示上一层i ~ (m - 1)位置的dp[i - 1][k] + pos][i - 1][k]最小值

二分当前状态的pos,若为p。比較左边lans[p - 1]与右边lans[p]的最小值就可以

//#pragma comment(linker, "/STACK:102400000,102400000")
//HEAD
#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
#include <algorithm>

#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <cstdlib>

using namespace std;
//LOOP
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FED(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
//STL
#define PB push_back
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)

#define FF(i, a, b) for(int i = (a); i < (b); ++i)
#define FD(i, b, a) for(int i = (b) - 1; i >= (a); --i)
#define CPY(a, b) memcpy(a, b, sizeof(a))
#define FC(it, c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
#define EQ(a, b) (fabs((a) - (b)) <= 1e-10)
#define ALL(c) (c).begin(), (c).end()
#define SZ(V) (int)V.size()
#define RIV(n, m, k, p) scanf("%d%d%d%d", &n, &m, &k, &p)
#define RV(n, m, k, p, q) scanf("%d%d%d%d%d", &n, &m, &k, &p, &q)
#define WI(n) printf("%d\n", n)
#define WS(s) printf("%s\n", s)
#define sqr(x) x * x
typedef long long LL;
typedef vector <int> VI;
typedef unsigned long long ULL;
const double eps = 1e-10;
const LL MOD = 1e9 + 7;

using namespace std;

const int maxn = 1010;
const int INF = 0x3f3f3f3f;

int dp[55][maxn], n, m, x;
int lm[maxn], rm[maxn], lans[maxn], rans[maxn];

struct Node{
    int pos, cost;
    int lval, rval;
    bool operator <(const Node& a) const
    {
        return pos < a.pos;
    }
}a[55][maxn];

void init(int u)
{

    REP(j, m)
    {
        a[u][j].lval = dp[u][j] - a[u][j].pos;
        a[u][j].rval = dp[u][j] + a[u][j].pos;
    }
    sort(a[u], a[u] + m);
    CLR(lm, INF), CLR(rm, INF);
    int s = 0, e = 0;
    lans[0] = lm[0] = a[u][0].lval, rans[m - 1] = rm[0] = a[u][m - 1].rval;
    FF(j, 1, m)
    {
        Node &v = a[u][j];
        if (v.lval > lm[e])   lm[++e] = v.lval;
        else
        {
            while (e >= 0 && v.lval < lm[e])  --e;
            lm[++e] = v.lval;
        }
        lans[j] = lm[0];
    }
    s = e = 0;
    FED(j, m - 2, 0)
    {
        Node &v = a[u][j];
        if (v.rval > rm[e])   rm[++e] = v.rval;
        else
        {
            while (e >= 0 && v.rval < rm[e])  --e;
            rm[++e] = v.rval;
        }
        rans[j] = rm[0];
    }
}

int main()
{
    int T;
    RI(T);
    while (T--)
    {
        RIII(n, m, x);
        REP(i, n)   REP(j, m)   RI(a[i][j].pos);
        REP(i, n)   REP(j, m)   RI(a[i][j].cost);
        REP(j, m)   dp[0][j] = abs(x - a[0][j].pos) + a[0][j].cost;
        FE(i, 1, n - 1)
        {
            init(i - 1);
            REP(j, m)
            {
                int p = lower_bound(a[i - 1], a[i - 1] + m, a[i][j]) - a[i - 1];
//                cout << "position  "<< p << endl;
                int lmin = INF, rmin = INF;
                if (p) lmin = lans[p - 1] + a[i][j].pos + a[i][j].cost;
                if (p < m)  rmin = rans[p] - a[i][j].pos + a[i][j].cost;
//                cout << "rans[p]:  " << rans[p] << endl;
//                cout << "lmin: " <<lmin << "rmin:  " << rmin << endl;
                dp[i][j] = min(lmin, rmin);
            }
        }
        int ans = INF;
        REP(j, m)   ans = min(dp[n - 1][j], ans);
        cout << ans << endl;
    }
    return 0;
}

这是水过的 1109ms

//#pragma comment(linker, "/STACK:102400000,102400000")
//HEAD
#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
#include <algorithm>

#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <cstdlib>

using namespace std;
//LOOP
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FED(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
//STL
#define PB push_back
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)

#define FF(i, a, b) for(int i = (a); i < (b); ++i)
#define FD(i, b, a) for(int i = (b) - 1; i >= (a); --i)
#define CPY(a, b) memcpy(a, b, sizeof(a))
#define FC(it, c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
#define EQ(a, b) (fabs((a) - (b)) <= 1e-10)
#define ALL(c) (c).begin(), (c).end()
#define SZ(V) (int)V.size()
#define RIV(n, m, k, p) scanf("%d%d%d%d", &n, &m, &k, &p)
#define RV(n, m, k, p, q) scanf("%d%d%d%d%d", &n, &m, &k, &p, &q)
#define WI(n) printf("%d\n", n)
#define WS(s) printf("%s\n", s)
#define sqr(x) x * x
typedef long long LL;
typedef vector <int> VI;
typedef unsigned long long ULL;
const double eps = 1e-10;
const LL MOD = 1e9 + 7;

using namespace std;

const int maxn = 1010;
const int INF = 0x3f3f3f3f;

inline int ABS(int x)   {if (x < 0) return -x; return x; }
int pos[55][maxn], cost[55][maxn];
int dp[55][maxn];

int main()
{
    int T, n, m, x;
    RI(T);
    while (T--)
    {
        RIII(n, m, x);
        REP(i, n)   REP(j, m)   RI(pos[i][j]);
        REP(i, n)   REP(j, m)   RI(cost[i][j]);
        REP(i, m)
            dp[0][i] = ABS(x - pos[0][i]) + cost[0][i];
        FE(i, 1, n - 1)
            REP(j, m)
            {
                int t = INF;
                  REP(k, m)
                {
//                    dp[i][j] = min(dp[i][j], dp[i - 1][k] + ABS(pos[i][j] - pos[i - 1][k]));
                    int x = dp[i - 1][k] + ABS(pos[i][j] - pos[i - 1][k]);
                    if (x < t)
                        t = x;
                }
                dp[i][j] = t + cost[i][j];
            }
        int ans = INF;
        REP(i, m)   ans = min(ans, dp[n - 1][i]);
        WI(ans);
    }
    return 0;
}

版权声明:本文博主原创文章,博客,未经同意不得转载。

时间: 2024-10-09 23:28:22

hdu4362 dp + 单调队列优化的相关文章

UESTC 594 我要长高 dp单调队列优化入门

//其实是个伪单调队列...渣渣刚入门 //戳这里:594 //dp[ i ][ j(现身高) ] = min(    dp[ i ][ k(现身高) ]  + fabs( j(现身高) - k(现身高) ) * C + ( j(现身高) - h[i](原身高) )  *( j(现身高) - h[i](原身高) )     ); 观察到可以单调队列优化,O(N * H * H)  —>  O(N * H) j >= k 时, dp[ i ][ j ] = min (    dp[ i ][ k

HDU 3401 Trade dp 单调队列优化

戳这里:3401 题意:给出第 i 天的股票买卖价格(APi,BPi),以及每天股票买卖的数量上限(ASi,BSi),要求任两次交易需要间隔 W 天以上,即第 i 天交易,第 i + W + 1 天才能再交易,求最多能赚多少钱 思路:dp[i][j] = max(dp[i - 1][j], max(dp[f][k] - (j - k) * APi[i]), max(dp[f][k] + (k - j) * BPi[i])); 从式子中观察出,若两天都持有股票数 j 时,之后的那一天所赚的钱不小于

P3084 [USACO13OPEN]照片Photo (dp+单调队列优化)

题目链接:传送门 题目: 题目描述 Farmer John has decided to assemble a panoramic photo of a lineup of his N cows (1 <= N <= 200,000), which, as always, are conveniently numbered from 1..N. Accordingly, he snapped M (1 <= M <= 100,000) photos, each covering a

【烽火传递】dp + 单调队列优化

题目描述 烽火台又称烽燧,是重要的防御设施,一般建在险要处或交通要道上.一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息:夜晚燃烧干柴,以火光传递军情.在某两座城市之间有 n 个烽火台,每个烽火台发出信号都有一定的代价.为了使情报准确的传递,在 m 个烽火台中至少要有一个发出信号.现输入 n.m 和每个烽火台发出的信号的代价,请计算总共最少需要多少代价,才能使敌军来袭之时,情报能在这两座城市之间准确的传递! 输入格式 第一行有两个数 n,m 分别表示 n 个烽火台,在任意连续的 m 个烽火台中至少

[BZOJ2442][Usaco2011 Open]修剪草坪 dp+单调队列优化

2442: [Usaco2011 Open]修剪草坪 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1118  Solved: 569[Submit][Status][Discuss] Description 在一年前赢得了小镇的最佳草坪比赛后,FJ变得很懒,再也没有修剪过草坪.现在,新一轮的最佳草坪比赛又开始了,FJ希望能够再次夺冠. 然而,FJ的草坪非常脏乱,因此,FJ只能够让他的奶牛来完成这项工作.FJ有N(1 <= N <= 100,0

vijos 1243 生产产品 DP + 单调队列优化

LINK 题意:有1个产品,m个步骤编号为1~m.步骤要在n个机器人的手中生产完成.其中,第i个步骤在第j个机器人手中的生产时间给定为$T[i][j]$,切换机器人消耗cost.步骤必须按顺序,同一个机器人不能连续完成超过l个步骤.求完成所有步骤的最短时间是多少.其中$m<=10^5$,$n<=5$,$l<=5*10^4$ 思路:这题用DP考虑易得一个转移方程$dp[i][j]=\min^{i-1}_{v=i-L}{(dp[v][x] + sum[i][j] - sum[v][j]) +

单调队列优化dp题目

附一链接,大多题型里面有,再附两题:https://blog.csdn.net/hjf1201/article/details/78729320 1.绿色通道 题目描述 Description <思远高考绿色通道>(Green Passage, GP)是唐山一中常用的练习册之一,其题量之大深受lsz等许多oiers的痛恨,其中又以数学绿色通道为最.2007年某月某日,soon-if (数学课代表),又一次宣布收这本作业,而lsz还一点也没有写-- 高二数学<绿色通道>总共有n道题目

poj3017 dp+单调队列

http://poj.org/problem?id=3017 Description Given an integer sequence { an } of length N, you are to cut the sequence into several parts every one of which is a consecutive subsequence of the original sequence. Every part must satisfy that the sum of

[Vijos 1243]生产产品(单调队列优化Dp)

Description 在经过一段时间的经营后,dd_engi的OI商店不满足于从别的供货商那里购买产品放上货架,而要开始自己生产产品了!产品的生产需要M个步骤,每一个步骤都可以在N台机器中的任何一台完成,但生产的步骤必须严格按顺序执行.由于这N台机器的性能不同,它们完成每一个步骤的所需时间也不同.机器i完成第j个步骤的时间为T[i,j].把半成品从一台机器上搬到另一台机器上也需要一定的时间K.同时,为了保证安全和产品的质量,每台机器最多只能连续完成产品的L个步骤.也就是说,如果有一台机器连续完