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 }
非做顽石不可,哪管他敬仰暗唾