http://poj.org/problem?id=1821

当我们在考虑内层循环j以及决策k的时候,我们可以把外层变量i看作定值,以此来优化dp状态转移方程。

题意 有n个工人准备铺m个连续的墙,每个工人有他必须图的一面墙壁Si,最多连续铺Li,每铺一个就花费Ci的钱,问最多要多少钱;

朴素算法很好想,就dp[i][j]维护i工人到这j层墙壁的最大值,对于每个工人去枚举他涂墙壁的开头和结尾然后更新即可。

时间复杂度O(NMM) M的范围是16000,很显然会T,我们考虑状态转移方程。

对于每个工人,dp[i][j]的更新是寻找一个k使得dp[i - 1][k - 1] + (j - k + 1 ) * P 最大;

在这个转移方程里,我们将i看作定值,除了状态变量j之外还有一个决策j,看似很难处理,我们将方程变形.

dp[i][j]的更新变为 max(dp[i - 1][k - 1] - (k - 1) * P) + j * P;

在这一层中,最大值的寻找仅和k有关,而k事实上对每一个i都是可以预处理出来的,在j查询的时候只有范围变动,问题就变成了常规的优化区间最大值的问题。

这里附上用ST表优化和单调队列优化的两种方法。

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
const double eps = 1e-;
const int maxn = ;
const int maxm = ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,tmp,K;
inline int read()
{
int now=;register char c=getchar();
for(;!isdigit(c);c=getchar());
for(;isdigit(c);now=now*+c-'',c=getchar());
return now;
}
struct Node{
int L,P,S;
}node[maxn];
int dp[][maxm];
bool cmp(Node a,Node b){
return a.S < b.S;
}
int DP[maxm][];
int mm[maxm];
int num[maxm];
void initRMQ(int n,int b[]){
mm[] = -;
for(int i = ; i <= n ; i ++){
mm[i] = ((i & (i - )) == ) ? mm[i - ] + :mm[i - ];
DP[i][] = b[i];
}
for(int j = ; j <= mm[n]; j ++){
for(int i = ; i + ( << j) - <= n ; i++){
DP[i][j] = max(DP[i][j - ],DP[i + ( << (j - ))][j - ]);
}
}
}
int rmq(int x,int y){
int k = mm[y - x + ];
return max(DP[x][k],DP[y - ( << k) + ][k]);
}
int main()
{
while(~Sca2(N,K)){
For(i,,K){
scanf("%d%d%d",&node[i].L,&node[i].P,&node[i].S);
}
sort(node + ,node + + K,cmp);
Mem(dp,);
For(i,,K){
Mem(num,);
Mem(dp[i & ],);
for(int k = max(node[i].S - node[i].L + ,); k <= node[i].S; k ++){
num[k] = dp[i - & ][k - ] - node[i].P * (k - );
}
initRMQ(node[i].S,num);
For(j,,N){
dp[i & ][j] = max(dp[i - & ][j],dp[i & ][j - ]);
if(j >= node[i].S && j <= node[i].S + node[i].L - ){
dp[i & ][j] = max(dp[i & ][j],rmq(max(j - node[i].L + ,),node[i].S) + node[i].P * j);
}
}
}
Pri(dp[K & ][N]);
}
#ifdef VSCode
system("pause");
#endif
return ;
}

ST表优化

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
const double eps = 1e-;
const int maxn = ;
const int maxm = ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,tmp,K;
inline int read()
{
int now=;register char c=getchar();
for(;!isdigit(c);c=getchar());
for(;isdigit(c);now=now*+c-'',c=getchar());
return now;
}
struct Node{
int L,P,S;
}node[maxn];
int dp[][maxm];
bool cmp(Node a,Node b){
return a.S < b.S;
}
int Queue[maxm];
int head,tail;
int main()
{
while(~Sca2(N,K)){
For(i,,K){
scanf("%d%d%d",&node[i].L,&node[i].P,&node[i].S);
}
sort(node + ,node + + K,cmp);
Mem(dp,);
For(i,,K){
head = ; tail = ;
Mem(dp[i & ],);
for(int k = max(node[i].S - node[i].L + ,); k <= node[i].S; k ++){
int ans = dp[i - & ][k - ] - node[i].P * (k - );
while(head <= tail && dp[i - & ][Queue[tail] - ] - node[i].P * (Queue[tail] - )<= ans) tail--;
Queue[++tail] = k;
}
For(j,,N){
dp[i & ][j] = max(dp[i - & ][j],dp[i & ][j - ]);
if(j >= node[i].S){
while(head <= tail && Queue[head] < j - node[i].L + ) head++;
if(head <= tail) dp[i & ][j] = max(dp[i & ][j],dp[i - & ][Queue[head] - ] + (j - Queue[head] + ) * node[i].P);
}
}
}
Pri(dp[K & ][N]);
}
#ifdef VSCode
system("pause");
#endif
return ;
}

单调队列优化

值得一提的是单调队列的查询和处理的时间都是线性的,总时间复杂度为O(NM),而ST表的预处理要用到nlnn,所以用时会比ST表快一些

POJ1821 单调队列//ST表 优化dp的更多相关文章

  1. P6087 [JSOI2015]送礼物 01分数规划+单调队列+ST表

    P6087 [JSOI2015]送礼物 01分数规划+单调队列+ST表 题目背景 \(JYY\) 和 \(CX\) 的结婚纪念日即将到来,\(JYY\) 来到萌萌开的礼品店选购纪念礼物. 萌萌的礼品店 ...

  2. HDU 4123 Bob's Race:树的直径 + 单调队列 + st表

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4123 题意: 给你一棵树,n个节点,每条边有长度. 然后有m个询问,每个询问给定一个q值. 设dis[ ...

  3. Luogu P1198 [JSOI2008]最大数 单调队列/ST表

    开一个单调队列,下标递增,值递减. 然后在上面二分最大数. 如果加上并查集可以做到接近线性. 还有一种是插入一个数然后,从后向前更新ST表. #include<cstdio> #inclu ...

  4. Codevs 4373 窗口(线段树 单调队列 st表)

    4373 窗口 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 黄金 Gold 题目描述 Description 给你一个长度为N的数组,一个长为K的滑动的窗体从最左移至最右端,你只 ...

  5. APIO2010特别行动队(单调队列、斜率优化)

    其实这题一看知道应该是DP,再一看数据范围肯定就是单调队列了. 不过我还不太懂神马单调队列.斜率优化…… 附上天牛的题解:http://www.cnblogs.com/neverforget/arch ...

  6. [bzoj4540][Hnoi2016][序列] (莫队算法+单调栈+st表)

    Description 给定长度为n的序列:a1,a2,…,an,记为a[1:n].类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,…,ar-1,ar.若1≤l≤s≤t≤r≤n,则称a ...

  7. Max answer(单调栈+ST表)

    Max answer https://nanti.jisuanke.com/t/38228 Alice has a magic array. She suggests that the value o ...

  8. BZOJ3879:SvT(后缀数组,单调栈,ST表)

    Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始 ...

  9. BZOJ4199 [Noi2015]品酒大会 【后缀数组 + 单调栈 + ST表】

    题目 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品 酒家"和"首席猎手"两个奖项,吸 ...

随机推荐

  1. vue的 v-for 循环中图片加载路径问题

    先看一下产品需求,如下图所示, 产品要求图片和它的名称一一对应,本来是非常简单的需求,后台直接返回图片路径和名称,前台直接读取就可以了,但是我们没有存储图片的服务器,再加上是一个实验性的需求,图片需要 ...

  2. 【数学建模】day09-聚类分析

    0. 多元分析之聚类分析. 聚类分析是一种定量方法,从数据的角度,对样本或指标进行分类,进而进行更好的分析. 分为Q型聚类和R型聚类. 1. Q型聚类分析是对样本进行分类.有若干样本,我们把这些样本分 ...

  3. JAVA优先级队列元素输出顺序测试

    package code.test; import java.util.Comparator; import java.util.Iterator; import java.util.Priority ...

  4. HTML5-Audio-基础篇

    播放音频文件 //control属性添加播放.暂停和音量控件<audio controls> <source src="horse.ogg" type=" ...

  5. Vmware 控制脚本

    #_*_ coding:utf8 _*_ import sys,time import yaml import re import os import ssl import random import ...

  6. Codeforces Round #432 Div. 1

    A:大胆猜想合法点不会很多,于是暴力检验,一旦发现不合法就break,可以random_shuffle一下. #include<iostream> #include<cstdio&g ...

  7. 【XSY2715】回文串 树链剖分 回文自动机

    题目描述 有一个字符串\(s\),长度为\(n\).有\(m\)个操作: \(addl ~c\):在\(s\)左边加上一个字符\(c\) \(addr~c\):在\(s\)右边加上一个字符 \(tra ...

  8. IDEA如何查看maven的依赖结构

    打开方式: 方法一:该工具有个Maven Projects窗口,一般在右侧能够找到,如果没有可以从菜单栏打开:View>Tool Windows>Maven Projects:选择要分析的 ...

  9. 网络流相关知识点以及题目//POJ1273 POJ 3436 POJ2112 POJ 1149

    首先来认识一下网络流中最大流的问题 给定一个有向图G=(V,E),把图中的边看做成管道,边权看做成每根管道能通过的最大流量(容量),给定源点s和汇点t,在源点有一个水源,在汇点有一个蓄水池,问s-t的 ...

  10. 对于submit text3运行Python脚本的解决方法

    先抛出一些配置信息吧 电脑安装了Python2和Python3两种版本,并且还改了exe文件的名字,可能这与默认的submit text3配置不同了吧,导致错误. 先抛出一些错误吧 首先,自动CTRL ...