@codeforces - 455E@ Function
@description@
已知 a 序列,并给定以下关系:
f(1, j) = a_j & (1 \le j \le n) \\
f(i, j) = \min\{f(i - 1, j), f(i - 1, j - 1)\} + a_j & (2 \le i \le j \le n)
\end{cases}\]
给定 m 次询问 (xi, yi),求 f(xi, yi) 的值。
Input
第一行一个整数 n (1 ≤ n ≤ 10^5) — a 序列的大小。
接下来一行 n 个整数 a[1], a[2], ..., a[n] (0 ≤ a[i] ≤ 10^4)。
接下来一行一个整数 m (1 ≤ m ≤ 10^5),询问的个数。
接下来 m 行每行包含两个整数 xi, yi (1 ≤ xi ≤ yi ≤ n),表示求 f(xi, yi) 的值。
Output
输出 m 行,表示每组询问对应的答案。
Examples
Input
6
2 2 3 4 3 4
4
4 5
3 4
3 4
2 3
Output
12
9
9
5
Input
7
1 3 2 3 4 0 2
4
4 5
2 3
1 4
4 6
Output
11
4
3
0
@solution@
考虑那个看起来像 dp 的式子 f(i, j) 的实际意义:
从 j 开始往前选一段连续的区间 [x, j],保证 a[x] ~ a[j] 都至少被选一次,选出共 i 个数。并求这 i 个数之和的最小值。
然后考虑分析性质。
除了 a[x] ~ a[j] 都至少选一次这些固定的选择,其他可用的选择应该都选择 [x, j] 中的最小值。
假如说 a[x] 不是最小值,则我们可以把 a[x] 删掉,将多出来的可用选择用于最小值。因此左端点一定为最小值。
记 s 为 a 的前缀和,则此时代价为 s[j] - s[x-1] + (i - (j-x+1))*a[x]。
因为左端点不为最小值时,肯定不优。所以我们问题转为求 s[j] - s[x-1] + (i - (j-x+1))*a[x] 的最小值 (j-i+1 <= x <= j)
注意到 s[j] - s[x-1] + (i - (j-x+1))*a[x] 是一个很经典的斜率式,可以写成 (j - i)*a[x] + (b - s[j]) = (x - 1)*a[x] - s[x-1],最小化 b 的值。
当 i, j 固定时,相当于我们每次拿一个斜率为 (j - i) 的直线去切点集 (a[x], (x - 1)*a[x] - s[x-1]) (j-i+1 <= x <= j),找最小截距。
如果想要去维护出每次询问中区间内的凸包,虽然询问只需要 O(log) 二分一下,但是构建凸包复杂度很大。
我们不妨考虑平衡一下复杂度:将一个询问在线段树上拆成 log 个询问,在线段树的每个结点中维护该结点对应的凸包。
则这样询问复杂度与凸包构建的复杂度就都可以平衡到 O(nlog^2n) 了。
@accepted code@
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define lch (x<<1)
#define rch (x<<1|1)
typedef long long ll;
const int MAXN = 100000;
struct point{
ll x, y;
point(ll _x=0, ll _y=0):x(_x), y(_y) {}
friend bool operator < (point a, point b) {
return (a.x == b.x) ? a.y < b.y : a.x < b.x;
}
};
long double slope(point a, point b) {
return ((long double)(b.y - a.y)) / (b.x - a.x);
}
int s[MAXN + 5], a[MAXN + 5], n, m;
int le[4*MAXN + 5], ri[4*MAXN + 5];
vector<point>A[4*MAXN + 5], tmp;
void build(int x, int l, int r) {
le[x] = l, ri[x] = r; tmp.clear();
for(int i=l;i<=r;i++)
tmp.push_back(point(a[i], -s[i-1] + (i-1)*a[i]));
sort(tmp.begin(), tmp.end());
for(int i=0;i<tmp.size();i++) {
if( !A[x].size() ) A[x].push_back(tmp[i]);
else {
if( tmp[i].x != A[x][A[x].size() - 1].x ) {
while( A[x].size() >= 2 ) {
int m = A[x].size();
if( slope(A[x][m-2], A[x][m-1]) >= slope(A[x][m-1], tmp[i]) ) A[x].pop_back();
else break;
}
A[x].push_back(tmp[i]);
}
}
}
if( l == r ) return ;
int mid = (l + r) >> 1;
build(lch, l, mid), build(rch, mid + 1, r);
}
ll query(point a, int k) {return a.y - k*a.x;}
ll query(const vector<point>&v, int k) {
int l = 0, r = v.size() - 1;
while( l < r ) {
int mid = (l + r) >> 1;
if( slope(v[mid], v[mid + 1]) >= k ) r = mid;
else l = mid + 1;
}
return query(v[r], k);
}
ll query(int x, int l, int r, int k) {
if( l <= le[x] && ri[x] <= r )
return query(A[x], k);
int mid = (le[x] + ri[x]) >> 1;
if( r <= mid ) return query(lch, l, r, k);
else if( l > mid ) return query(rch, l, r, k);
else return min(query(lch, l, r, k), query(rch, l, r, k));
}
int main() {
scanf("%d", &n);
for(int i=1;i<=n;i++)
scanf("%d", &a[i]), s[i] = s[i-1] + a[i];
build(1, 1, n);
scanf("%d", &m);
for(int i=1;i<=m;i++) {
int x, y; scanf("%d%d", &x, &y);
/*int ans = inf;
for(int j=y;j>=y-x+1;j--)
ans = min(ans, int(Y(j) - (y-x)*X(j))); // b = y - kx, y = kx + b.
printf("%d\n", ans + s[y]);*/
printf("%lld\n", query(1, y-x+1, y, y-x) + s[y]);
}
}
@details@
合并两个凸包的复杂度等价于构建凸包的复杂度,即凸包不适合进行合并。
这使得凸包并不大适合线段树等依赖于信息合并的数据结构(本题是利用线段树拆解询问,而不是利用线段树合并凸包)。
但某种意义上来说,凸包挺适合分块的。
@codeforces - 455E@ Function的更多相关文章
- codeforces 455E
题目:http://codeforces.com/problemset/problem/455/E 题意:给定数组a,及f的定义: f[1][j] = a[j]; 1 <= j <= n ...
- CF数据结构练习
1. CF 438D The Child and Sequence 大意: n元素序列, m个操作: 1,询问区间和. 2,区间对m取模. 3,单点修改 维护最大值, 取模时暴力对所有>m的数取 ...
- 通过百度echarts实现数据图表展示功能
现在我们在工作中,在开发中都会或多或少的用到图表统计数据显示给用户.通过图表可以很直观的,直接的将数据呈现出来.这里我就介绍说一下利用百度开源的echarts图表技术实现的具体功能. 1.对于不太理解 ...
- Educational Codeforces Round 13 D:Iterated Linear Function(数论)
http://codeforces.com/contest/678/problem/D D. Iterated Linear Function Consider a linear function f ...
- Codeforces Gym 100187M M. Heaviside Function two pointer
M. Heaviside Function Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100187/ ...
- Codeforces Round #245 (Div. 1) 429D - Tricky Function 最近点对
D. Tricky Function Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 codeforces.com/problemset/problem/42 ...
- Codeforces Round #277 (Div. 2) A. Calculating Function 水题
A. Calculating Function Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/4 ...
- Codeforces 837E. Vasya's Function
http://codeforces.com/problemset/problem/837/E 题意: f(a, 0) = 0; f(a, b) = 1 + f(a, b - gcd(a, b)) ...
- Codeforces 837E Vasya's Function - 数论
Vasya is studying number theory. He has denoted a function f(a, b) such that: f(a, 0) = 0; f(a, b) = ...
随机推荐
- @import vs #import - iOS 7
It's a new feature called Modules or "semantic import". There's more info in the WWDC 2013 ...
- spring cloud深入学习(五)-----熔断器Hystrix
雪崩效应 在微服务架构中通常会有多个服务层调用,基础服务的故障可能会导致级联故障,进而造成整个系统不可用的情况,这种现象被称为服务雪崩效应.服务雪崩效应是一种因“服务提供者”的不可用导致“服务消费者” ...
- LintCode_41 最大子数组
题目 给定一个整数数组,找到一个具有最大和的子数组,返回其最大和. 注意事项 子数组最少包含一个数 样例 给出数组[−2,2,−3,4,−1,2,1,−5,3],符合要求的子数组为[4,−1,2,1] ...
- 通过Struts2Web应用框架深入理解MVC
Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet. 一.用法简介: 1.Eclipse新建Dynamic Web Project, 项目名:Struts2Pro ...
- Python学习笔记(六)Python组合数据类型
在之前我们学会了数字类型,包括整数类型.浮点类型和复数类型,这些类型仅能表示一个数据,这种表示单一数据的类型称为基本数据类型.然而,实际计算中却存在大量同时处理多个数据的情况,这种需要将多个数据有效组 ...
- Lab2 新增的细节
entry.S 新增加了这个入口函数 bootloader 加载完成后 将执行 kern_entry 而非lab1 中的kern_init defs.h 使用了 ({})宏定义的方式,并且执行了一行定 ...
- 词袋和 TF-IDF 模型
做文本分类等问题的时,需要从大量语料中提取特征,并将这些文本特征变换为数值特征.常用的有词袋模型和TF-IDF 模型 1.词袋模型 词袋模型是最原始的一类特征集,忽略掉了文本的语法和语序,用一组无序的 ...
- vue使用填坑之:model和v-model的区别
v-model通常用于input的双向数据绑定 <input v-model="parentMsg">,也可以实现子组件到父组件数据的双向数据绑定:首先说说v-mode ...
- 层次分析法MATLAB
输入成对比较矩阵,输出权重值和一致性检验结果. disp('请输入判断矩阵A(n阶)'); A=input('A='); [n,n]=size(A); x=ones(n,100); y=ones(n, ...
- passive的作用和原理
passived到底有什么用? passived主要用于优化浏览器页面滚动的性能,让页面滚动更顺滑~~ passived产生的历史时间线 addEventListener():大家都是认识的,为dom ...