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 数学 + 单调栈 + 优化的更多相关文章

  1. Codeforces 601B. Lipshitz Sequence(单调栈)

    Codeforces 601B. Lipshitz Sequence 题意:,q个询问,每次询问给出l,r,求a数组[l,r]中所有子区间的L值的和. 思路:首先要观察到,斜率最大值只会出现在相邻两点 ...

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

    题目链接:http://codeforces.com/problemset/problem/442/C 题目大意:一个数列,有n个元素.你可以做n-2次操作,每次操作去除一个数字,并且得到这个数字两边 ...

  3. 【P2422】良好的感觉(单调栈优化DP//奇怪的暴力)

    话说正解是单调栈优化DP,然而貌似根据某种玄学的推算,这个题暴力出解貌似也是可以的.首先,我们枚举所有的点作为最小点,然后横向展开,遇到更小的就停止...然后再操作一下,看上去时间O(N^2),然而由 ...

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

    改了两天,终于将T1,T3毒瘤题改完了... T1 施工(单调栈优化DP) 考场上只想到了n*hmaxn*hmaxn的DP,用线段树优化一下变成n*hmaxn*log但显然不是正解 正解是很**的单调 ...

  5. 【BZOJ1345】[Baltic2007]序列问题Sequence 贪心+单调栈

    [BZOJ1345][Baltic2007]序列问题Sequence Description 对于一个给定的序列a1, …, an,我们对它进行一个操作reduce(i),该操作将数列中的元素ai和a ...

  6. 2019年杭电多校第二场 1002题Beauty Of Unimodal Sequence(LIS+单调栈)

    题目链接 传送门 思路 首先我们对\(a\)正反各跑一边\(LIS\),记录每个位置在前一半的\(LIS\)中应该放的位置\(ans1[i]\),后一半的位置\(ans2[i]\). 对于字典序最小的 ...

  7. [poj3017] Cut the Sequence (DP + 单调队列优化 + 平衡树优化)

    DP + 单调队列优化 + 平衡树 好题 Description Given an integer sequence { an } of length N, you are to cut the se ...

  8. poj3017 Cut the Sequence[平衡树+单调队列优化]

    这里已经讲得很清楚了. 本質上是決策點與區間最大值有一定關係,於是用单调队列来维护决策集合(而不是常规的),然后在决策集合中选取最小值. 然后觉得这题方法还是很重要的.没写平衡树,用优先队列(堆)来维 ...

  9. 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 ...

随机推荐

  1. if return 和 if else

    最近看Node.js实战中,有一段代码是优化之前使用if else,优化之后是使用if return,我不知道if return是不是效率比if else高. 优化前: if(err){ handle ...

  2. linux命令启动服务(tomcat服务或者jar包)

    启动tomcat: 1.方式一:直接启动 ./startup.sh 2.方式二:nohup ./startup.sh & 启动后,关闭当前客户端连接,重新启动一个查看是 否已经启动 启动jar ...

  3. POJ3436 ACM Computer Factory —— 最大流

    题目链接:https://vjudge.net/problem/POJ-3436 ACM Computer Factory Time Limit: 1000MS   Memory Limit: 655 ...

  4. 代码块、继承、this、super、final(java基础知识八)

    1.代码块的概述和分类 * A:代码块概述 * 在Java中,使用{}括起来的代码被称为代码块.* B:代码块分类 * 根据其位置和声明的不同,可以分为局部代码块,构造代码块,静态代码块,同步代码块( ...

  5. android TextView 设置部分文字背景色 和 文字颜色

    通过SpannableStringBuilder来实现,它就像html里边的元素改变指定文字的文字颜色或背景色 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...

  6. Python mutilprocess模块之第二种创建进程方法--继承Process类

    '''创建新的进程的第二种方法: 使用类的方式,可以自己定义一个类,继承Process类,每次实例化这个类的时候, 就等于实例化一个进程对象 '''from multiprocessing impor ...

  7. Quartz 2D(常用API函数、绘制图形、点线模式)

    Quzrtz 2D 绘图的核心 API 是 CGContextRef ,它专门用于绘制各种图形. 绘制图形关键是两步: 1.获取 CGContextRef ; 2.调用 CGContextRef 的方 ...

  8. js 将json字符串转换为json对象的方法解析-转

    例如: JSON字符串:var str1 = '{ "name": "cxh", "sex": "man" }'; JS ...

  9. 由mysql分区想到的分表分库的方案

    在分区分库分表前一定要了解分区分库分表的动机. 对实时性要求比较高的场景,使用数据库的分区分表分库. 对实时性要求不高的场景,可以考虑使用索引库(es/solr)或者大数据hadoop平台来解决(如数 ...

  10. c语言基本数据类型相关

    1byte = 8bit  数据类型  比特长度  位长度  IO表达  int  2/4  16/32  %d   unsigned (int)  2/4  16/32  %u  short int ...