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. Y7000联想拯救者gtx1050Ti安装cuda9.0

    安装cuda经常会遇到安装失败的问题,原因大部分都是由于驱动不一致引起的,接下来我们分两步讲解 1. 安装驱动失败 原因:nvidia官网提供的驱动都是通用的,针对特殊设备可能出现不兼容问题,方法很简 ...

  2. ImportError: No module named google.protobuf.internal

    下载: protobuf-3.3.0 设置路径:export PYTHONPATH=/gruntdata/lihaiyang/local/protobuf-3.3.0/python:$PYTHONPA ...

  3. Military Problem CodeForces 1006E (dfs序)

    J - Military Problem CodeForces - 1006E 就是一道dfs序的问题 给定一个树, 然后有q次询问. 每次给出u,k, 求以u为根的子树经过深搜的第k个儿子,如果一个 ...

  4. windows开关机事件

    开关机事件.xml <ViewerConfig> <QueryConfig> <QueryParams> <Simple> <BySource&g ...

  5. Java中的CopyOnWrite

    CopyOnWrite简称COW,是一种程序设计的一种优化的策略方法,他开始的思想就是大家一起共享一件东西或商品,当一个人想要改这个事物原有的状态时,会重新复制一份出去,然后再新的事物上面改他所需要的 ...

  6. centos 7创建ss服务(方式一)

    一:安装PIP,由于安装的是python 版本的ss,所以需要先安装PIP: $ curl "https://bootstrap.pypa.io/get-pip.py" -o &q ...

  7. 51Nod1778 小Q的集合 【组合数】【Lucas定理】

    题目分析: 题解好高深...... 我给一个辣鸡做法算了,题解真的看不懂. 注意到方差恒为$0$,那么其实就是要我们求$\sum_{i=0}^{n}\binom{n}{i}(i^k-(n-i)^k)^ ...

  8. 【正睿oi省选十连测】第一场

    四小时写了两个暴力??自闭 [原来这就是神仙们的分量Orz rank 56/75 可以说是无比垃圾了 下周目标:进步十名?[大雾 T1 题意:有n个点的图 点有点权Ai 也有点权Bi = A_1 + ...

  9. iptables(1)

    iptables配置文件:/etc/sysconfig/iptables 确认开启路由转发功能方法1:/sbin/sysctl -w net.ipv4.ip_forward=1方法2:echo 1 & ...

  10. TCP/UDP区别

    一:1. 大体上来说,TCP和UDP都是通过Internet发送数据包的协议.都建立在Internet协议上.就是无论你是用TCP协议还是用UDP协议发送数据包,都会被发送到IP地址: 2.数据包的处 ...