CF 602 D. Lipshitz Sequence 数学 + 单调栈 + 优化
http://codeforces.com/contest/602/problem/D
这题需要注意到的是,对于三个点(x1, y1)和(x2, y2)和(x3, y3)。如果要算出区间[1, 3]的L(h)函数的最大值,则一定不会是
通过(y3 - y1) / (x3 - x1)算出。因为很简单,通过(x2, y2)作为辅助点,数值将会更加大。
然后设dis[i]表示abs(a[i + 1] - a[i])。那么区间[L, R]的最大值就是在dis[]中,[L, R - 1]数值的最大值。
因为,不断套用上面那个结论,先从两个点的时候出发,a[2] - a[1]就是最大,然后,如果三个点,那么可能是a[3] - a[2]和a[2] - a[1]中的较大者。4个点的时候同理,每次只需要用前一个的最大值和a[new] - a[new - 1]比较,取最大的即可。
比如样例
a[]: 1、5、2、9、1、3、4、2、1、7
dis[]: 4、3、7、8、2、1、2、1、6
但是还是要枚举每个子区间,那么复杂度还是不变。
那么要把问题转化下,转化成求以dis[i]为最大值的区间数有多少个。
那么可以用单调栈维护出tonext[i]表示右边第一个大于dis[i]的数。topre[i]表示左边第一个大于dis[i]的数。
注意判断不要超过[L, R]的范围。
然后两个数值相乘,就是dis[i]为最大值的区间数。
但是有点bug。比如上面的 2、1、2、1
算了第一个2,那么后面的2就不应该重复计算。那么需要标记是否vis[]
如果vis[],那么需要找到第一个等于2的数就行了,所以我用了三次单调栈。
感觉有点复杂。
但是真正自己想到了的话,写代码是很愉快的。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int maxn = + ;
int a[maxn];
int dis[maxn];
int tonext[maxn];
int topre[maxn];
int topresec[maxn];
int vis[maxn];
int tdis[maxn];
struct node {
int id;
int val;
}STACK[maxn];
void work() {
int n, q;
// IOS;
// cin >> n >> q;
scanf("%d%d", &n, &q);
for (int i = ; i <= n; ++i) {
// cin >> a[i];
scanf("%d", &a[i]);
}
for (int i = ; i <= n - ; ++i) {
dis[i] = abs(a[i + ] - a[i]);
tdis[i] = dis[i];
}
sort(tdis + , tdis + + n - );
dis[n] = inf;
int top = ;
STACK[top].id = ;
STACK[top].val = dis[];
for (int i = ; i <= n; ++i) {
while (top >= && dis[i] > STACK[top].val) {
tonext[STACK[top].id] = i;
top--;
}
++top;
STACK[top].id = i;
STACK[top].val = dis[i];
}
// for (int i = 1; i <= n; ++i) {
// printf("%d ", tonext[i]);
// }
dis[] = inf;
top = ;
STACK[top].id = n - ;
STACK[top].val = dis[n - ];
for (int i = n - ; i >= ; --i) {
while (top >= && dis[i] > STACK[top].val) {
topre[STACK[top].id] = i;
--top;
}
++top;
STACK[top].id = i;
STACK[top].val = dis[i];
} dis[] = inf;
top = ;
STACK[top].val = dis[n - ];
STACK[top].id = n - ;
for (int i = n - ; i >= ; --i) {
while (top >= && dis[i] >= STACK[top].val) {
topresec[STACK[top].id] = i;
--top;
}
++top;
STACK[top].id = i;
STACK[top].val = dis[i];
}
// for (int i = 1; i <= n; ++i) {
// printf("%d ", topresec[i]);
// }
int cnt = ;
while (q--) {
int L, R;
scanf("%d%d", &L, &R);
LL ans = ;
for (int i = L; i <= R - ; ++i) {
int be = max(L - , topre[i]);
int en = min(R, tonext[i]);
int pos = lower_bound(tdis + , tdis + + n - , dis[i]) - tdis;
if (vis[pos] == cnt) {
be = max(L - , topresec[i]);
}
vis[pos] = cnt;
ans += (LL)dis[i] * (i - be) * (en - i);
}
cnt++;
printf("%I64d\n", ans);
}
} int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
work();
return ;
}
2017年3月9日 17:10:38
现在 回顾起这题,当时的写法确实有点复杂,其实要解决那个bug,只需要维护toNext[i]表示大于dis[i]这个数字的第一个位置。toPre[i]表示不小于dis[i]这个数字的位置即可。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>
const int maxn = + ;
int a[maxn];
int dis[maxn];
int n, q;
struct Stack {
int val, id;
}st[maxn];
int toNext[maxn], toPre[maxn];
void init() {
for (int i = ; i <= n - ; ++i) {
dis[i] = abs(a[i + ] - a[i]);
}
dis[n] = inf;
int top = ;
for (int i = ; i <= n; ++i) {
while (top >= && dis[i] > st[top].val) {
toNext[st[top].id] = i;
--top;
}
++top;
st[top].val = dis[i];
st[top].id = i;
}
top = ;
dis[] = inf;
for (int i = n - ; i >= ; --i) {
while (top >= && dis[i] >= st[top].val) {
toPre[st[top].id] = i;
--top;
}
++top;
st[top].val = dis[i];
st[top].id = i;
}
}
LL calc(int be, int en) {
LL ans = ;
for (int i = be; i <= en; ++i) {
int L = max(be, toPre[i] + );
int R = min(en, toNext[i] - );
ans += 1LL * dis[i] * (i - L + ) * (R - i + );
}
return ans;
}
void work() {
scanf("%d%d", &n, &q);
for (int i = ; i <= n; ++i) {
scanf("%d", &a[i]);
}
init();
// for (int i = 1; i <= n - 1; ++i) {
// cout << toNext[i] << " ";
// }
// for (int i = 1; i <= n - 1; ++i) {
// cout << toPre[i] << " ";
// }
// for (int i = 1; i <= n - 1; ++i) {
// cout << dis[i] << " ";
// }
while (q--) {
int L, R;
scanf("%d%d", &L, &R);
printf("%I64d\n", calc(L, R - ));
}
} int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
work();
return ;
}
CF 602 D. Lipshitz Sequence 数学 + 单调栈 + 优化的更多相关文章
- Codeforces 601B. Lipshitz Sequence(单调栈)
Codeforces 601B. Lipshitz Sequence 题意:,q个询问,每次询问给出l,r,求a数组[l,r]中所有子区间的L值的和. 思路:首先要观察到,斜率最大值只会出现在相邻两点 ...
- [CF442C] Artem and Array (贪心+单调栈优化)
题目链接:http://codeforces.com/problemset/problem/442/C 题目大意:一个数列,有n个元素.你可以做n-2次操作,每次操作去除一个数字,并且得到这个数字两边 ...
- 【P2422】良好的感觉(单调栈优化DP//奇怪的暴力)
话说正解是单调栈优化DP,然而貌似根据某种玄学的推算,这个题暴力出解貌似也是可以的.首先,我们枚举所有的点作为最小点,然后横向展开,遇到更小的就停止...然后再操作一下,看上去时间O(N^2),然而由 ...
- csp-s模拟测试50(9.22)「施工(单调栈优化DP)」·「蔬菜(二维莫队???)」·「联盟(树上直径)」
改了两天,终于将T1,T3毒瘤题改完了... T1 施工(单调栈优化DP) 考场上只想到了n*hmaxn*hmaxn的DP,用线段树优化一下变成n*hmaxn*log但显然不是正解 正解是很**的单调 ...
- 【BZOJ1345】[Baltic2007]序列问题Sequence 贪心+单调栈
[BZOJ1345][Baltic2007]序列问题Sequence Description 对于一个给定的序列a1, …, an,我们对它进行一个操作reduce(i),该操作将数列中的元素ai和a ...
- 2019年杭电多校第二场 1002题Beauty Of Unimodal Sequence(LIS+单调栈)
题目链接 传送门 思路 首先我们对\(a\)正反各跑一边\(LIS\),记录每个位置在前一半的\(LIS\)中应该放的位置\(ans1[i]\),后一半的位置\(ans2[i]\). 对于字典序最小的 ...
- [poj3017] Cut the Sequence (DP + 单调队列优化 + 平衡树优化)
DP + 单调队列优化 + 平衡树 好题 Description Given an integer sequence { an } of length N, you are to cut the se ...
- poj3017 Cut the Sequence[平衡树+单调队列优化]
这里已经讲得很清楚了. 本質上是決策點與區間最大值有一定關係,於是用单调队列来维护决策集合(而不是常规的),然后在决策集合中选取最小值. 然后觉得这题方法还是很重要的.没写平衡树,用优先队列(堆)来维 ...
- POJ - 3415 Common Substrings(后缀数组求长度不小于 k 的公共子串的个数+单调栈优化)
Description A substring of a string T is defined as: T( i, k)= TiTi+1... Ti+k-1, 1≤ i≤ i+k-1≤| T|. G ...
随机推荐
- lint (software)
lint (software) - Wikipedia https://en.wikipedia.org/wiki/Lint_(software) A linter or lint refers to ...
- 编写自定义PE结构的程序(如何手写一个PE,高级编译器都是编译好的PE头部,例如MASM,TASM等,NASM,FASM是低级编译器.可以自定义结构)
正在学PE结构...感谢个位大哥的文章和资料...这里先说声谢谢 一般高级编译器都是编译好的PE头部,例如MASM,TASM等一直都说NASM,FASM是低级编译器.可以自定义结构但是苦于无人发布相关 ...
- 推断View是否显示在界面上
我们都知道ViewController有viewWillAppear和viewDidAppear等关于页面生命周期的方法,用来对视图做一些管理,比方页面出现时怎么样,页面消失时怎么样.. 可是对于Vi ...
- HDU 6118 度度熊的交易计划 【最小费用最大流】 (2017"百度之星"程序设计大赛 - 初赛(B))
度度熊的交易计划 Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...
- aop+自定义注解
自定义注解,并且实现,需要两个文件: 自定义注解类: package com.clc.server.annotation; import java.lang.annotation.ElementTyp ...
- 关于LAMP配置Let’s Encrypt SSL证书
昨天建站,买VPS,先装了LAMP,部署wordpress,测试OK了,然后才买的域名,申请SSL证书. 结果Let’s Encrypt cerbot申请证书遇到了麻烦,--apache参数怎么也识别 ...
- Map实现缓存
为什么要使用缓存 缓存最终的目的是为减轻服务端压力,减少网络传输请求 客户端缓存 浏览器访问自带缓存~~ 页面缓存 浏览器缓存 App客户端缓存 IOS 前端开发 底层都有缓存技术的 ( ...
- eclipse、idea切换大小写的快捷键
idea : ctrl+shift+U切换大小写 eclipse : ctrl+shift+X 切换成大写 ctrl+shift+Y 切换成小写
- Eos的Wasm智能合约的局限性
官方只支持用C++写智能合约 用C++写智能合约门槛过高,会把许多开发者挡在门外,C++的复杂性也会让智能合约的设计变得困难. Wasm智能合约的效率并不是最优 由于C++最终也是编译成wasm字节码 ...
- Oracle:varchar2、nvarchar2 字段类型的区别
一直对varchar2.nvarchar2 字段类型存储字符数不清楚,现测试如下: 创建TT测试表 测试脚本如下: insert into tt values('1111','1111'); --- ...