http://hihocoder.com/problemset/problem/1831?sid=1390457
描述
80 Days is an interesting game based on Jules Verne's science fiction "Around the World in Eighty Days". In this game, you have to manage the limited money and time.
Now we simplified the game as below:
There are n cities on a circle around the world which are numbered from 1 to n by their order on the circle. When you reach the city i at the first time, you will get ai dollars (ai can even be negative), and if you want to go to the next city on the circle, you should pay bi dollars. At the beginning you have c dollars.
The goal of this game is to choose a city as start point, then go along the circle and visit all the city once, and finally return to the start point. During the trip, the money you have must be no less than zero.
Here comes a question: to complete the trip, which city will you choose to be the start city?
If there are multiple answers, please output the one with the smallest number.
输入
The first line of the input is an integer T (T ≤ 100), the number of test cases.
For each test case, the first line contains two integers n and c (1 ≤ n ≤ 106, 0 ≤ c ≤ 109). The second line contains n integers a1, …, an (-109 ≤ ai ≤ 109), and the third line contains n integers b1, …, bn (0 ≤ bi ≤ 109).
It's guaranteed that the sum of n of all test cases is less than 106
输出
For each test case, output the start city you should choose.
提示
For test case 1, both city 2 and 3 could be chosen as start point, 2 has smaller number. But if you start at city 1, you can't go anywhere.
For test case 2, start from which city seems doesn't matter, you just don't have enough money to complete a trip.
样例输入
2
3 0
3 4 5
5 4 3
3 100
-3 -4 -5
30 40 50
样例输出
2
-1
题意:就是n个点,当到达某个点时可以获得 a[ i ] 价值并且失去 b[ i ]价值,有个人有一个初始价值,问能否找到一个起点,让这个人能够从起点出发遍历所有点后回到起点。(当这个人身上的价值 < 0 的时候就无法再走)
题解:two point可做,但是这里我用的是 线段树维护区间最小前缀和。
把每个点得到和失去的价值的差值记录下来,并且对他们求一个前缀和(后文统一叫差值前缀和)。 可以很容易的想到,对于一个起点来说,在他遍历其他点的过程中,如果前缀和小于零,意味着他在行走的过程中碰到了入不敷出的情况,这时候就无法行动了。
由于之前求的差值前缀和是 i 从1开始的,但是我们需要的是对于一个点 i ,从这个点开始的前缀和满足都大于0,这个点才可以作为起点。但是对每个点 i 求前缀和对于这题得要 n^2复杂度,因此要更改策略。
因为差值前缀和不一定是升序的,因此我们只要找到 i ~n的最小前缀和,试想:只要这个最小前缀和都满足条件(>=0)了,那么其他点肯定都能满足,如果这个最小前缀和不满足,那么只要一个点不满足,那么就整体都无法满足。因此线段树维护 i ~ n 的最小前缀和就行了。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll n,k;
const int mx = 1e6 + 5;
ll a[mx],b[mx],c[mx];
ll MIN[mx<<2];
ll minn;
void pushup(int rt){
MIN[rt] = min(MIN[rt<<1],MIN[rt<<1|1]);
}
void build(int l,int r,int rt){
if(l == r){
MIN[rt] = c[l];
return ;
}
int mid = (l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
pushup(rt);
}
void query(int l,int r,int rt,int L,int R){
if(l >= L && r <= R){
minn = min(minn, MIN[rt]);
return ;
}
int mid = (l+r)>>1;
if(L <= mid) query(l,mid,rt<<1,L,R);
if(R > mid) query(mid+1,r,rt<<1|1,L,R);
}
int main(){
int t;
cin>>t;
while(t--){
memset(MIN,0,sizeof(MIN));
scanf("%lld%lld",&n,&k);
ll sum1 = 0, sum2 = 0;
for(int i = 1; i <= n; i++){
scanf("%lld",&a[i]);
sum1 += a[i];
}
for(int i = 1; i <= n; i++){
scanf("%lld",&b[i]);
sum2 += b[i];
}
if(sum1 + k < sum2){
printf("-1\n");
continue;
}
for(int i = 1; i <= n; i++){
c[i] = a[i] - b[i];
}
for(int i = 2; i <= n; i++){
c[i] = c[i-1] + c[i];
}
build(1,n,1);
int flag = 0;
for(int i = 1; i <= n; i++){
minn = 99999999999;
query(1,n,1,i,n);
if(minn+k-c[i-1] >= 0){ //这一步的判断其实就是求从i开始的前缀和
printf("%d\n",i);
flag = 1;
break;
}
}
if(!flag) printf("-1\n");
}
}
探讨了一个基于儒勒·凡尔纳科幻小说《八十天环游地球》的游戏简化版策略,玩家需管理金钱与时间,选择最佳起点以完成游戏目标。
487

被折叠的 条评论
为什么被折叠?



