POJ1821 单调队列//ST表 优化dp
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的更多相关文章
- P6087 [JSOI2015]送礼物 01分数规划+单调队列+ST表
P6087 [JSOI2015]送礼物 01分数规划+单调队列+ST表 题目背景 \(JYY\) 和 \(CX\) 的结婚纪念日即将到来,\(JYY\) 来到萌萌开的礼品店选购纪念礼物. 萌萌的礼品店 ...
- HDU 4123 Bob's Race:树的直径 + 单调队列 + st表
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4123 题意: 给你一棵树,n个节点,每条边有长度. 然后有m个询问,每个询问给定一个q值. 设dis[ ...
- Luogu P1198 [JSOI2008]最大数 单调队列/ST表
开一个单调队列,下标递增,值递减. 然后在上面二分最大数. 如果加上并查集可以做到接近线性. 还有一种是插入一个数然后,从后向前更新ST表. #include<cstdio> #inclu ...
- Codevs 4373 窗口(线段树 单调队列 st表)
4373 窗口 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 黄金 Gold 题目描述 Description 给你一个长度为N的数组,一个长为K的滑动的窗体从最左移至最右端,你只 ...
- APIO2010特别行动队(单调队列、斜率优化)
其实这题一看知道应该是DP,再一看数据范围肯定就是单调队列了. 不过我还不太懂神马单调队列.斜率优化…… 附上天牛的题解:http://www.cnblogs.com/neverforget/arch ...
- [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 ...
- Max answer(单调栈+ST表)
Max answer https://nanti.jisuanke.com/t/38228 Alice has a magic array. She suggests that the value o ...
- BZOJ3879:SvT(后缀数组,单调栈,ST表)
Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始 ...
- BZOJ4199 [Noi2015]品酒大会 【后缀数组 + 单调栈 + ST表】
题目 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品 酒家"和"首席猎手"两个奖项,吸 ...
随机推荐
- codeforces732C
Sanatorium CodeForces - 732C Vasiliy spent his vacation in a sanatorium, came back and found that he ...
- Python中数字之间的进制转换
Python中的数据转换 在python中可以通过内置方法进行相应的进制转换,但需记得转化成非十进制时,都会将数字转化成字符串 转化成二进制 a = 10 #声明数字,默认十进制 b = bin(a) ...
- 解决vscode egg调试出现: this socket has been ended by other party【转】
如果是最新的1.22 方案一 回退版本到1.21.1 https://code.visualstudio.com/updates/v1_21 方案二 退而求其次, 更改debug配置, 待官方或egg ...
- 解决面板里没有network manager图标的问题 ,也就是在桌面环境下,没有那个网络图标
在安装好了桌面之后,竟然发现没有那个连接网络的图标,本来想连接无限网络.可是.......如果去手动命令行下去配置这个连接wifi有些麻烦,所以我还是去找解决办法了 我执行了一条命令就解决了 gcon ...
- [Codeforces757G]Can Bash Save the Day?——动态点分治(可持久化点分树)
题目链接: Codeforces757G 题目大意:给出一棵n个点的树及一个1~n的排列pi,边有边权,有q次操作: 1 l r x 求 $\sum\limits_{i=l}^{r}dis(p_{i} ...
- C# 两个类是否继承关系
IsAssignableFrom:确定指定类型的实例是否可以分配给当前类型的实例 B继承自A static void Main(string[] args) { Type a = typeof(A); ...
- Android 永久保存简单数据
转载: http://blog.csdn.net/xzlawin/article/details/45959033 方法1: 存数据: SharedPreferences userInfo = thi ...
- C Looooops POJ - 2115 (exgcd)
一个编译器之谜:我们被给了一段C++语言风格的循环 for(int i=A;i!=B;i+=C) 内容; 其中所有数都是k位二进制数,即所有数时膜2^k意义下的.我们的目标时球出 内容 被执行了多少次 ...
- VueCLI3如何更改安装时的包管理器为yarn或npm
在执行 vue create project 后如果显示如下 npm run serve 则表示你使用的是npm创建的项目. 如果显示如下 yarn serve 则表示此项目为yarn创建. 那如何切 ...
- BZOJ 2521: [Shoi2010]最小生成树(最小割)
题意 对于某一条无向图中的指定边 \((a, b)\) , 求出至少需要多少次操作.可以保证 \((a, b)\) 边在这个无向图的最小生成树中. 一次操作指: 先选择一条图中的边 \((u, v)\ ...