UOJ #586. 旅行问题

【题目描述】:

John 打算驾驶一辆汽车周游一个环形公路。公路上总共有n个车站,每个站都有若干升汽油(有的站可能油量为零),每升油可以让汽车行驶一千米。

John 必须从某个车站出发,一直按顺时针(或逆时针)方向走遍所有的车站,并回到起点。在一开始的时候,汽车内油量为零,John 每到一个车站就把该站所有的油都带上(起点站亦是如此),行驶过程中不能出现没有油的情况。

任务:判断以每个车站为起点能否按条件成功周游一周。
【输入描述】:

第一行是一个整数n,表示环形公路上的车站数;

接下来n行,每行两个整数pi,di分别表示表示第i号车站的存油量和第i号车站到下一站的距离。
【输出描述】:

输出共n行,如果从第i号车站出发,一直按顺时针(或逆时针)方向行驶,能够成功周游一圈,则在第i行输出 TAK,否则输出 NIE。
【样例输入】:

5
3 1
1 2
5 2
0 1
5 4

【样例输出】:

TAK
NIE
TAK
NIE
TAK

【时间限制、数据范围及描述】:

时间:2s 空间:512M

30%的数据:3<=n<=10^4;

70%的数据:3<=n<=10^5;

100%的数据:3<=n<=10^6;0<=pi<=2×10^9;0<di<=2×10^9;

本题的暴力做法是将数组拓宽2倍,对其做一遍前缀和,每次对长度为n的序列进行区间减法,减去前一位数,即得到此长度为n的序列的前缀和,
然后看其中最小的是否>=0,一共做n次,然后统计答案即可.(这里的区间减法可以直接简化成求区间最小,然后判断其是否>=前一位数)
正解做法即用单调队列维护区间最小的数即可.
注意:每个站到下一个站的距离是顺时针给出的.

Code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<ctime>
using namespace std;
const int N=2000005;
long long sum[N];
int n,p[N],d[N],ok[N],Q[N];
void DP1(){
	int head=1,tail=0;
	for(int i=1;i<=n;i++){
		while(head<=tail&&sum[Q[tail]]>=sum[i]){
			--tail;
		}
		Q[++tail]=i;
	}
	for(int i=n+1;i<=2*n;i++){
		while(head<=tail&&sum[Q[tail]]>=sum[i]){
			--tail;
		}
		Q[++tail]=i;
		while(head<=tail&&Q[head]<=i-n-1){
			++head;
		}
		if(sum[Q[head]]>=sum[i-n-1]){
			ok[i-n]=1;
		}
	}
}
void DP2(){
	int head=1,tail=0;
	for(int i=n*2;i>=n+1;i--){
		while(head<=tail&&sum[Q[tail]]>=sum[i]){
			--tail;
		}
		Q[++tail]=i;
	}
	for(int i=n;i>=1;i--){
		while(head<=tail&&sum[Q[tail]]>=sum[i]){
			--tail;
		}
		Q[++tail]=i;
		while(head<=tail&&Q[head]>=i+n){
			++head;
		}
		if(sum[Q[head]]>=sum[i+n]){
			ok[i]=1;
		}
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d%d",&p[i],&d[i]);
		p[i+n]=p[i];
		d[i+n]=d[i];
		sum[i]=sum[i-1]+p[i]-d[i];
	}
	for(int i=n+1;i<=n*2;i++){
		sum[i]=sum[i-1]+p[i]-d[i];
	}
	DP1();
	for(int i=n*2;i>=1;i--){
		sum[i]=sum[i+1]+p[i+1]-d[i];
	}
	DP2();
	for(int i=1;i<=n;i++){
		if(ok[i]){
			printf("TAK\n");
		}
		else{
			printf("NIE\n");
		}
	}
	return 0;
}
posted @ 2019-09-17 01:47  prestige  阅读(161)  评论(0)    收藏  举报