2022赛前模测11C 旅游

这篇博客讨论了一个关于算法的问题,小欧在旅游过程中可以跳过最多z个城市,每个非起始城市花费a元,也可能在某些城市通过卖艺赚钱。问题求解旅行结束后,小欧最多能比出发时多出多少钱。博主提出了O(n^2)和O(nlogn)两种解决方案,使用线段树优化以提高效率。
摘要由CSDN通过智能技术生成

小欧参加了一档节目,获得特等奖,可以免费旅游若干个城市。机票住宿全部由主办方承担,但其它的消费就得自己承担了。
他的旅游行程是从第 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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值