loj 10178 POI2004 旅行问题

传送门:loj 10178

分析

因为是环形,开两倍

油量 - 到下一个站的距离 = 剩余油量

如果在一圈之中有哪一个时刻的前缀和小于零,那么这一点不能作为起点(sum[j] - sum[i-1]<0,i为起点,j为其他站点)

所以sum[j]需要大于sum[i]

可以用单调队列优化:长度限制为n,sum单调递增

如果队首 + n等于当前编号,则已经一圈了,标记为1

代码

 1 /****************************
 2 User:Mandy.H.Y
 3 Language:c++
 4 Problem:
 5 Algorithm:
 6 Date:
 7 ****************************/
 8 #include<bits/stdc++.h>
 9 
10 using namespace std;
11 
12 const int maxn = 1e6 + 5;
13 
14 int n,l,r;
15 long long sum[maxn];
16 long long p[maxn<<1],p1[maxn << 1];
17 //p顺时针,p1逆时针 
18 int q[maxn];
19 bool vis[maxn];
20 
21 template<class T>inline void read(T &x){
22     x = 0;bool flag = 0;char ch = getchar();
23     while(!isdigit(ch)) flag |= ch == '-',ch = getchar();
24     while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
25     if(flag) x = -x;
26 }
27 
28 template<class T>void putch(const T x){
29     if(x > 9) putch(x / 10);
30     putchar(x % 10 | 48);
31 } 
32 
33 template<class T>void put(const T x){
34     if(x < 0) putchar('-'),putch(-x);
35     else putch(x);
36 }
37 
38 void file(){
39     freopen("data3.in","r",stdin);
40 //    freopen("10178.out","w",stdout);
41 }
42 
43 void readdata(){
44     read(n);
45     long long d,pre = 0;
46     for(int i = 1;i <= n; ++ i){
47         read(p[i]);p1[i] = p[i];
48         read(d);
49         p[i] -= d;//油量 - 距离 = 剩余油量 
50         p1[i] -= pre;
51         p1[i + n] = p1[i];//环形开两倍 
52         p[i + n] = p[i];
53         pre = d;
54     }
55     p1[1] -= pre;
56     p1[n + 1] = p1[1];//逆时针1减去n 
57 }
58 
59 void work(){
60     //保证sum单调递增,不然油量会剩余负
61     //以i为起点走到j的剩余油量:sum[j] - sum[i-1]; 
62     for(int i = 1;i <= n + n; ++ i){//顺时针 
63         while(l < r && q[l] + n == i) vis[q[l]] = 1,l++;//看是否一圈完毕 
64         sum[i] = sum[i-1] + p[i];//前缀和 
65 //        while(l < r && sum[i] - sum[q[l] - 1] < 0) l++;
66         while(l < r && sum[i] - sum[q[r - 1] - 1] < 0) r--;
67         //后面的油量剩余为负 ,则弹出 
68         //记得 - 1 :q[r - 1] - 1 
69         if(p[i] >= 0) q[r++] = i;//如果本身为负,不能作为起点 
70     }
71 
72     l = r = 0;
73     sum[n + n + 1] = 0;//清空 
74 
75     for(int i = n + n;i >= 1; -- i){//逆时针 
76         while(l < r && q[l] - n == i) vis[q[l] - n] = 1,l++;
77         sum[i] = sum[i+1] + p1[i];//用p1 
78 //        while(l < r && sum[i] - sum[q[l] + 1] < 0) l++;
79         while(l < r && sum[i] - sum[q[r - 1] + 1] < 0) r--;//记得要 + 1 ,是  < 
80         if(p1[i] >= 0) q[r++] = i;        
81     }
82     
83     for(int i = 1;i <= n; ++ i){
84         if(vis[i]) puts("TAK");
85         else puts("NIE");
86     }
87 }
88 
89 int main(){
90 //    file();
91     readdata();
92     work();
93     return 0;
94 }
View Code

 

posted @ 2019-08-30 16:45  Mandy_H_Y  阅读(457)  评论(0编辑  收藏  举报