ACM/ICPC 2018亚洲区预选赛北京赛站网络赛 hihocoder #1831 : 80 Days(拆点+线段树)

                                                                 80 Days

时间限制:1000ms

单点时限:1000ms

内存限制:256MB

描述

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个城市,和一个初始钱数C。每个城市有进城能获得的价值a[ i ]和出城需要花费的代价b[ i ]。每次可以从当前城市 i 走到下一个相邻的城市 i + 1或者,从城市n走到城市 1.

询问的是,让我们选择一个起始点走一圈后回到起始点,限制条件是在不停的行走中钱数不能小于零。(回到i点的那一刻不重复计算i点位置的a[i]和b[i])。由于会存在多个这样的起始点,输出编号最小的那个。

 

三、思路

要满足这样的条件,可以先把每个城市拆成两个点,一个表示进城的瞬间手上的拥有的钱数,另一个表示出城的瞬间手上拥有的钱数。并对这个数组扩大一倍,模拟走回到起始点的操作。

然后求一个前缀和,枚举[ l , r ]长度为2*n的区间,用线段树来找出区间的最小值 minn 。若这个最小值加上初始值C并且减去前缀 l - 1的结果大于零,则表示找出了一段可行的区间。复杂度就是一个求前缀和,加上n*logn.

 

四、代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define inf 0x3f3f3f3f3f3f3f
typedef long long LL;
int gcd(int a, int b) { return a == 0 ? b : gcd(b % a, a); }



const int maxn = 1000005*4;	//线段树范围要开4倍
int T, n;
LL jin[maxn/2], chu[maxn/2], C;
struct Tree
{
	int l, r;
	LL sum,minn;
};
Tree node[maxn * 4];		//node[maxn]为线段树处理数组
int a[maxn * 2];			//a[maxn]为原数组
void update(int i)
{
	node[i].sum = node[i << 1].sum + node[(i << 1) | 1].sum;
	node[i].minn = min(node[i << 1].minn, node[(i << 1) | 1].minn);
}
void build(int i, int l, int r)
{
	node[i].l = l; node[i].r = r;
	if (l == r)
	{
		node[i].minn = a[l];
		node[i].sum = a[l];
		return;
	}
	int mid = (l + r) / 2;
	build(i << 1, l, mid);
	build((i << 1) | 1, mid + 1, r);
	update(i);
}
LL getmin(int i, int l, int r)
{
	if (node[i].l == l&&node[i].r == r)
		return node[i].minn;
	int mid = (node[i].l + node[i].r) / 2;
	if (r <= mid) return getmin(i << 1, l, r);
	else if (l>mid) return getmin((i << 1) | 1, l, r);
	else return min(getmin(i << 1, l, mid), getmin((i << 1) | 1, mid + 1, r));
}

int main()
{
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d %lld", &n,&C);
		for (int i = 1; i <= n; i++)
		{
			scanf("%lld", &jin[i]);
		}
		for (int i = n + 1, j = 1; i <= n + n; i++, j++)
			jin[i] = jin[j];
		for (int i = 1; i <= n; i++)
		{
			scanf("%lld", &chu[i]);
		}
		for (int i = n + 1, j = 1; i <= n + n; i++, j++)
			chu[i] = chu[j];

		for (int i = 1,j=1; i <= 2 * n; i++)
		{
			a[j] = a[j - 1] + jin[i]; j++;
			a[j] = a[j - 1] - chu[i]; j++;
		}
		build(1, 1, 4 * n);
		bool tag = false;
		for (int i = 1; i <= n; i++)
		{
			LL minn = getmin(1, (i - 1) * 2 + 1, (i - 1) * 2 + 2 * n);
			if (C + minn - a[(i - 1) * 2 ] >= 0)
			{
				printf("%d\n", i);
				tag = true;
				break;
			}
		}
		if (!tag)printf("-1\n");

	}

}

 

你可能感兴趣的:(ACM/ICPC 2018亚洲区预选赛北京赛站网络赛 hihocoder #1831 : 80 Days(拆点+线段树))