小欧参加了一档节目,获得特等奖,可以免费旅游若干个城市。机票住宿全部由主办方承担,但其它的消费就得自己承担了。
他的旅游行程是从第 x 个城市依次旅游到第 y 个城市。但是有时他觉得某些城市没有意思,这样他可以跳过一些城市,主办方承诺机票可以随时改签。但是他不想太早结束他的旅程,所以,他给自己规定,最多跳过 z 个城市,即最远可以从第 i 跳到第 i+z 个城市。
在一个城市游玩总是需要买买买和吃吃吃的。除城市 x 之外,在任何一个城市,小欧都会刚好花掉 a 元,不多不少。有时小欧会格外喜欢某个城市,他可能会在那个城市卖个艺,挣点外快。但即使挣了再多的钱,他也只会花掉 a 元。
现在小欧想知道,经过这一趟旅游,他最多能比出发时多出多少钱。
输入
第一行输入5个整数 x,y,z,a,n,其中,n表示他喜欢的城市的数目。(1≤n≤1e5)
之后n行,每行包含两个正整数c[i],m[i],表示小欧如果在第c[i]个城市卖艺,可以赚m[i]的钱。保证c[i]按递增顺序输入。
输出
输出一个整数,表示小欧旅行完以后最多能够比他出发时多出多少钱。答案可以为负。
数据范围
对于20%的数据,N≤1000;
另有30%的数据,z≤100;
对于100%的数据,
1≤m[i],a,z≤1e9,1≤n≤1e5, 0≤x≤c[i]≤y≤1e9.
f[i]为到达第i个喜欢的城市时,最多比出发时多的钱数。
则有f[i] = max{f[j] + ceil(c[i] - c[j]) / z * a + m[i]}, 时间复杂度O(n^2), 考虑优化。
设c[i] = k[i] * z + b[i], 其中0 ≤ b[i] < z,
f[i] = max{f[j] + (k[i] - k[j]) * a + ceil(b[i] - b[j]) / z * a + m[i],
b[i] > b[j]时,f[i] = max{f[j] + k[j] * a - (k[i] + 1) * a + m[i]},
b[i] ≤ b[j]时,f[i] = max{f[j] + k[j] * a - k[i] * a + m[i]},
线段树维护f[j] + k[j] * a,下标为b[j],即线段树的每个叶子节点存储一个同余类的信息,时间复杂度O(nlogn).
代码如下:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
inline int read() {
int x = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f = ch == '-', ch = getchar();
while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
return f ? -x : x;
}
const int N = 100010;
const ll inf = 2e18;
int x, y, z, a, n;
int c[N]; ll m[N], f[N];
int k[N], b[N], tmp[N], len;
struct Node {
int l, r; ll mx;
};
struct Seg