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 ...
随机推荐
- 新装Linux系统没有网卡驱动的解决办法和步骤
Linux下查看网卡驱动和版本信息 - CSDN博客 https://blog.csdn.net/guyan1101/article/details/72770424/ 检查网卡是否加载 - Linu ...
- Windows 7 繁体中文MSDN原版
Win7 SP1 64位旗舰版繁体版ISO镜像(香港):文件名:hk_windows_7_enterprise_with_sp1_x64_dvd_620688.isoSHA1:82D59B099333 ...
- sql索引原理以及优化
http://itindex.net/detail/52237-%E7%B4%A2%E5%BC%95-%E5%8E%9F%E7%90%86 http://itindex.net/detail/5171 ...
- Linux时间子系统之三:时间的维护者:timekeeper【转】
本文转载自:http://blog.csdn.net/droidphone/article/details/7989566 本系列文章的前两节讨论了用于计时的时钟源:clocksource,以及内核内 ...
- SDUT 3035 你猜我猜不猜你猜不猜(字符串 规律性)
你猜我猜不猜你猜不猜 Time Limit: 2000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描述 In the past 39th annual ACM in ...
- linux初级学习笔记十:linux grep及正则表达式!(视频序号:04_4)
本节学习的命令:grep 本节学习的技能: grep对文本的匹配 正则表达式的使用 知识点十:grep及正则表达式(4_4) grep,egrep,fgrep: grep: 根据模式搜索文本,并将符合 ...
- MYSQL进阶学习笔记二:MySQL存储过程和局部变量!(视频序号:进阶_4-6)
知识点三:MySQL存储过程和局部变量(4,5,6) 存储过程的创建: 创建存储过程的步骤: 首先选中数据库 改变分隔符,不让分号作为执行结束的标记.(通常情况下,改变分隔符命令 DELIMI ...
- CSS:清除浮动
周五去听css样式的培训,讲到float导致div不能被撑开的问题,特记录如下: 在写HTML代码的时候,如果有一个DIV作为外部容器,内部的DIV如果设置了float样式,则外部的容器DIV因为内部 ...
- 书写优雅的shell脚本(插曲)- /proc/${pid}/status
Linux中/proc/[pid]/status详细说明 博客分类: OS Linux多线程 [root@localhost ~]# cat /proc/self/status Name: cat ...
- codeforces 691F F. Couple Cover(组合计数)
题目链接: F. Couple Cover time limit per test 3 seconds memory limit per test 512 megabytes input standa ...