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;
}
时间: 2024-10-06 17:52:17

Gym 100646 F Tanks a Lot RMQ的相关文章

[2016-04-17][Gym][100947][F][black-white]

时间:2016-04-17 17:06:43 星期日 题目编号:[2016-04-17][Gym][100947][F][black-white] 题目大意:在一行格子中,有一个白棋和一个黑旗,每次移动一个,给出一个状态,白棋先移动,问最后胜利的人是水 分析: 只要白棋和黑棋始终保持奇数的间隔(即轮到白棋走的时候,黑白间隔奇数个),最后黑棋一定会被逼到角落,然后间隔不断减小(减小之和还是奇数间隔),最后黑棋败 #include<cstdio> using namespace std; int

codeforces Gym 100187F F - Doomsday 区间覆盖贪心

F. Doomsday Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100187/problem/F Description Doomsday comes in t units of time. In anticipation of such a significant event n people prepared m vaults in which, as they think, it will

Gym 100637F F. The Pool for Lucky Ones

F. The Pool for Lucky Ones Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100637/problem/F Description A new swimming pool has been built in Kazan for the forthcoming Water Sports World Championship. The pool has N lanes. Some

Codeforces gym 100685 F. Flood bfs

F. FloodTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100685/problem/F Description We all know that King Triton doesn't like us and therefore shipwrecks, hurricanes and tsunami do happen. But being bored with the same routine

Gym 100637F F. The Pool for Lucky Ones 暴力

F. The Pool for Lucky Ones Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100637/problem/F Description A new swimming pool has been built in Kazan for the forthcoming Water Sports World Championship. The pool has N lanes. Some

Codeforces Gym 100513F F. Ilya Muromets 线段树

F. Ilya Muromets Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100513/problem/F Description I Ilya Muromets is a legendary bogatyr. Right now he is struggling against Zmej Gorynych, a dragon with n heads numbered from 1 to nf

GYM 101173 F.Free Figurines(贪心||并查集)

原题链接 题意:俄罗斯套娃,给出一个初始状态和终止状态,问至少需要多少步操作才能实现状态转化 贪心做法如果完全拆掉再重装,答案是p[i]和q[i]中不为0的值的个数.现在要求寻找最小步数,显然要减去一些多余的步数.如果初始的一些链的前端是终止的某一条链的连续的一部分,那么这条链就不用被拆开再连上,这样每一个长度为x的链对答案的贡献就是-2*(x-1),对每条链进行同样的操作之后就是答案 #include <iostream> #include<cstdio> #include<

GYM 101128 F.Landscaping【最小割--还不懂】

题目大意:给你一个N*M的矩阵,其中"#"代表高地,"."代表低地,我们有N+M辆车,从高地转到低地需要花费A,我们使得高地变成低地或者是使得低地变成高地的花费为B.我们的车每列从上到下,每行从左到右行驶,问最小花费是多少. 其实我看不懂别人的解法,我也不会,先放这里. 思路: 很显然我们不能直接Dp,因为我们当前的块如果变化了,会对之前很多结果进行了影响,我们考虑多加维度取消这个后效性无果,不妨考虑网络流. 我们要求最小花费,不难想到最小割,那么考虑建图. ①首先

GYM 101350 F. Monkeying Around(线段树 or 思维)

F. Monkeying Around time limit per test 2.0 s memory limit per test 256 MB input standard input output standard output When the monkey professor leaves his class for a short time, all the monkeys go bananas. N monkeys are lined up sitting side by sid