暑假D9 T2 extra(单调栈优化DP)

题意

一条路被划分成了n段,每一段有一个高度,一个人有步幅k,代表他最多可以从第x段一步到第x+k段,当h[x]>h[x+k]时,不消耗体力,否则消耗一点体力,求最后到第n段路时最少消耗的体力,最初在第一段路。

对于 30%的数据,保证 T = 1;
对于另 20% 的数据,保证 N <= 500;
对于 100% 的数据,保证 n< = 1e6, T <= 10,ai在 int 内,0 < K <n。

题解

很容易想到转移方程 f[i]= h[i]<h[j] ? f[j] : f[j]+1 (i-k≤j<i)

怎么优化呢,对于高度不同的路,方程都不一样,该怎么去想。

如果方程一样的话,就是在一个长度为k的区间内找f最小的,那不就是单调栈吗?

但转移方程不同,考虑单调栈对于栈首的弹出只与他是否还属于这个区间有关,只要他还能管这个区间,他就是最优的,所以它与去掉不优解无关。我们去掉不优解是在队尾进行的,且每次比较队尾与当前要插入元素的某个值。

那么考虑什么时候队尾的值一定不比当前元素的值优:当两者f值相同时,如果队尾更矮肯定不优,因为在值相同的情况下,他更可能带来1的代价;

那么队尾元素的f比当前元素的f大呢,队尾也是不优的,或者说可以被代替,因为即使当前元素更矮,它带来了1的代价,得到的答案也是≤队尾得到的答案;

队尾元素的f更小就不能弹掉,和上面相同,即使当前元素更高,队尾元素得到的答案也≤当前元素得到答案。

#include<bits/stdc++.h>
using namespace std;

const int maxn=1000005;
int n,m,a[maxn];
int q[maxn],h,t;
int f[maxn];

void nice(){
    int k;scanf("%d",&k);
    h=1;t=0;
    q[++t]=1;
    f[1]=0;
    for(int i=2;i<=n;i++){
        while(h<=t&&i-q[h]>k) h++;
        f[i]= a[i]>=a[q[h]] ? f[q[h]]+1 : f[q[h]];
        while(h<=t&&((a[i]>a[q[t]]&&f[i]==f[q[t]])||(f[i]<f[q[t]]))) t--;
        q[++t]=i;
    }
    printf("%d\n",f[n]);
}

int main(){
    freopen("extra.in","r",stdin);
    freopen("extra.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    scanf("%d",&m);
    while(m--) nice();
}
/*9
4 6 3 6 3 7 2 6 5
2
2
5*/

原文地址:https://www.cnblogs.com/sto324/p/11222433.html

时间: 2024-07-30 11:18:00

暑假D9 T2 extra(单调栈优化DP)的相关文章

csp-s模拟测试50(9.22)「施工(单调栈优化DP)」&#183;「蔬菜(二维莫队???)」&#183;「联盟(树上直径)」

改了两天,终于将T1,T3毒瘤题改完了... T1 施工(单调栈优化DP) 考场上只想到了n*hmaxn*hmaxn的DP,用线段树优化一下变成n*hmaxn*log但显然不是正解 正解是很**的单调栈 可以想象到最优情况一定是将两端高于中间的一段平原填成一段平的坑,不然如果坑内存在高度差那么我们即使只将一部分抬升也肯定没有用处,并且如果中间的坑已经高于了两端,再向上升也肯定不优,然后就中间的坑可以很很小,也可以很长,对于这个模型我们首先想到n^2*h的DP 设当前表示的f[i]表示当前到了i节

POJ 3415 Common Substrings(长度不小于k 的公共子串的个数--后缀数组+单调栈优化)

题意:给定两个字符串A 和B,求长度不小于k 的公共子串的个数(可以相同). 样例1: A="xx",B="xx",k=1,长度不小于k 的公共子串的个数是5. 样例2: A ="aababaa",B ="abaabaa",k=2,长度不小于k 的公共子串的个数是22. 思路: 如果i后缀与j后缀的LCP长度为L, 在L不小于K的情况下, 它对答案的贡献为L - K + 1. 于是我们可以将两个串连起来, 中间加个奇葩的分隔符

HDU 4122 Alice&#39;s mooncake shop 单调队列优化dp

Alice's mooncake shop Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4122 Description The Mid-Autumn Festival, also known as the Moon Festival or Zhongqiu Festival is a popular harvest festival celebrated by Ch

Tyvj1305最大子序和(单调队列优化dp)

描述 输入一个长度为n的整数序列,从中找出一段不超过M的连续子序列,使得整个序列的和最大. 例如 1,-3,5,1,-2,3 当m=4时,S=5+1-2+3=7当m=2或m=3时,S=5+1=6 输入格式 第一行两个数n,m第二行有n个数,要求在n个数找到最大子序和 输出格式 一个数,数出他们的最大子序和 测试样例1 输入 6 4 1 -3 5 1 -2 3 输出 7 备注 数据范围:100%满足n,m<=300000 是不超过m,不是选m个!!!!! /* 单调队列优化dp 单调队列维护的是前

bzoj1855: [Scoi2010]股票交易--单调队列优化DP

单调队列优化DP的模板题 不难列出DP方程: 对于买入的情况 由于dp[i][j]=max{dp[i-w-1][k]+k*Ap[i]-j*Ap[i]} AP[i]*j是固定的,在队列中维护dp[i-w-1][k]+k*Ap[i]的单调性即可 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int maxn = 2010; 6 int

[CF442C] Artem and Array (贪心+单调栈优化)

题目链接:http://codeforces.com/problemset/problem/442/C 题目大意:一个数列,有n个元素.你可以做n-2次操作,每次操作去除一个数字,并且得到这个数字两边相邻的数最小的分数.问你最多得到多少分. 将高度绘图,去除V的情况. 用单调栈优化,每个元素进栈一次,出栈一次.线性时间. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include

1855: [Scoi2010]股票交易[单调队列优化DP]

1855: [Scoi2010]股票交易 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1083  Solved: 519[Submit][Status][Discuss] Description 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每个i,都有APi>=

BZOJ 1855 股票交易(单调队列优化DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1855 题意:最近lxhgww又迷上了投资股票, 通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每 个i,都有APi>=BPi),但是每天不能无限制地交易,于是股票交易所规定第i天的一次买入至多只能购买ASi股,一次卖出至多只能卖出BS

【单调队列优化dp】uestc 594 我要长高

http://acm.uestc.edu.cn/#/problem/show/594 [AC] 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=5e4+2; 5 const int inf=0x3f3f3f3f; 6 int n,c; 7 int cur; 8 int dp[2][maxn]; 9 int q[maxn]; 10 int main() 11 { 1