Gym 100646 F Tanks a Lot RMQ
Problem F: Tanks a Lot Imagine you have a car with a very large gas tank - large enough to hold whatever amount you need. You are traveling on a circular route on which there are a number of gas stations. The total gas in all the stations is exactly the amount it takes to travel around the circuit once. When you arrive at a gas station, you add all of that station’s gas to your tank. Starting with an empty tank, it turns out there is at least one station to start, and a direction (clockwise or counter-clockwise) where you can make it around the circuit. (On the way home, you might ponder why this is the case - but trust us, it is.) Given the distance around the circuit, the locations of the gas stations, and the number of miles your car could go using just the gas at each station, find all the stations and directions you can start at and make it around the circuit. Input There will be a sequence of test cases. Each test case begins with a line containing two positive integers c and s, representing the total circumference, in miles, of the circle and the total number of gas stations. Following this are s pairs of integers t and m. In each pair, t is an integer between 0 and c−1 measuring the clockwise location (from some arbitrary fixed point on the circle) around the circumference of one of the gas stations and m is the number of miles that can be driven using all of the gas at the station. All of the locations are distinct and the maximum value of c is 100,000. The last test case is followed by a pair of 0’s. Output For each test case, print the test case number (in the format shown in the example below) followed by a list of pairs of values in the form i d, where i is the gas station location and d is either C, CC, or CCC, indicating that, when starting with an empty tank, it is possible to drive from location i around in a clockwise (C) direction, counterclockwise (CC) direction, or either direction (CCC), returning to location i. List the stations in order of increasing location. Sample Input 10 4 2 3 4 3 6 1 9 3 5 5 0 1 4 1 2 1 3 1 1 1 0 0 Sample Output Case 1: 2 C 4 CC 9 C Case 2: 0 CCC 1 CCC 2 CCC 3 CCC 4 CCC
题意:给你一个长度为c的环,环上面有m个加油站,各个加油站油的总和刚好够你在环上面跑一圈,一开始你的车没有油,现在你可以选一个加油站作为出发点并获得该加油站的所有油,然后选择顺时针或逆时针行走,没经过一个加油站你可以获得那里的油,问是否可以最终回到选择为起始的那个加油站。 这m个加油站有哪些是可以作为起始点的,可以的话应该顺时针出发还是逆时针出发还是两个方向都可以?
思路:对于环可以头尾接一遍变成直线,将加油站按顺序排列。设need_i为只用第i个加油站的油到第i+1个加油站还需要的油量, 比如1(2)---》 5(3)---》7(1) 那么从油站1到油站5还欠了2, 即need为-2, 从油站5到油站7多了2,即need为2
那么对于第i个加油站能作为起点,相当于从i开始的need数组的前缀和不能为负数。 那么我们可以直接做一遍前缀和,然后对于一个区间[l,r],要想以l位置为起点的前缀和在这个区间没有负数,相当于sum[l-1]<=min(sum[k]) l<=k<=r 相当于这个区间的值都减去sum[l-1] 查询区间最小值可以用rmq处理
对于逆时针方向 做法就完全一样了,逆着求一下need数组。
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <vector> #include <string> #include <stack> #include <cmath> #include <cstdlib> #include <iostream> #include <map> #include <set> using namespace std; const int INF = 0x3f3f3f3f; typedef long long ll; const int N = 5e5 + 100; int sum1[N], sum2[N]; int dir[N]; int dp[N][20]; int mm[N]; int n, k; struct node { int t, m; friend bool operator < (node a, node b) { return a.t < b.t; }; }; node g[N]; void initRMQ(int nn, int b[]) { mm[0] = -1; for(int i = 1; i <= nn; ++i) { mm[i] = ((i & (i - 1)) == 0) ? mm[i - 1] + 1 : mm[i - 1]; dp[i][0] = b[i]; } for(int j = 1; j <= mm[nn]; ++j) for(int i = 1; i + (1 << j) - 1 <= nn; ++i) dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j-1))][j - 1]); } int rmq(int x, int y) { int k = mm[y - x + 1]; return min(dp[x][k], dp[y - (1 << k) + 1][k]); } void init1() { int T = k * 2; memset(dir, 0, sizeof dir); sum1[1] = 0; for(int i = 2; i <= T; ++i) { int s = (g[i].t - g[i - 1].t + n) % n; sum1[i - 1] = sum1[i - 2] + g[i-1].m - s; } initRMQ(T, sum1); } void init2() { int T = k * 2; sum2[1] = sum2[T + 1] = 0; for(int i = T; i > 1; --i) { int s = (g[i].t - g[i - 1].t + n) % n; sum2[i] = sum2[i + 1] + g[i].m - s; } initRMQ(T, sum2); } void solve1() { for(int i = 1; i <= k; ++i) { if(sum1[i - 1] <= rmq(i, i + k - 1)) { dir[ g[i].t ] = 1; } } } void solve2() { int T = k * 2; for(int i = T; i > T - k; --i) { if(sum2[i + 1] <= rmq(i - k + 1, i)) { if(dir[ g[i].t ]) dir[ g[i].t ] = 3; else dir[ g[i].t ] = 2; } } } int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); #endif int cas = 1; while(~scanf("%d%d", &n, &k)) { if(n == 0 && k == 0) break; for(int i = 1; i <= k; ++i) { scanf("%d%d", &g[i].t, &g[i].m); } sort(g + 1, g + 1 + k); for(int i = 1; i <= k; ++i) { g[i + k].t = g[i].t; g[i + k].m = g[i].m; } // for(int i = 1; i <= k * 2; ++i) printf("%d %d\n", g[i].t, g[i].m); init1(); solve1(); init2(); solve2(); printf("Case %d: ", cas++); for(int i = 1; i <= k; ++i) { if(dir[ g[i].t ] == 1) printf("%d C ", g[i].t); if(dir[ g[i].t ] == 2) printf("%d CC ", g[i].t); if(dir[ g[i].t ] == 3) printf("%d CCC ", g[i].t); } puts(""); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
2015-08-15 hdu 4000Fruit Ninja 树状数组