7485-旅行问题
题目传送
环形问题,先破环成链,即用
例如,假设
序列编号为
能否到达取决于油量是否够,所以途中的任意一个加油站,油量必须大于等于路程,才能到达下一个加油站。
设
先考虑顺时针情况,
那么在区间
破环成链和前缀和
for(int i = 1; i <= n; i++){
cin>>p[i]>>d[i];
p[n + i] = p[i];
d[n + i] = d[i];
}
for(int i = 1; i <= 2 * n; i++) sum[i] = sum[i-1] + p[i] - d[i];
顺时针
顺时针,单调队列优化,滑动窗口做法。
int head = 0, tail = 0;
for(int i = 1; i < 2 * n; i++){
while(head <= tail && i - q[head] >= n) head++;
while(head <= tail && sum[q[tail]] >= sum[i]) tail--;
q[++tail] = i;
if(i >= n && sum[q[head]]-sum[i-n] >= 0) ans[i - n + 1] = 1; //i为1的时候表示走向2,所以i为n的时候表示走向1
}
因为是顺时针,所以当
逆时针
逆时针,可以先计算出后缀和,然后从后往前扫描,同时进行单调队列优化,大致差不多,细节需注意,毕竟方向反了,代码不可能一样。
后缀和计算方式,第
所以后缀和计算如下:
for(int i = 2 * n; i > 0; i--) sum[i] = sum[i + 1] + p[i] - d[i - 1];
反向扫描,单调队列优化,注意方向。
head = 0, tail = 0;q[head] = 2 * n + 1; //初始化
for(int i = 2 * n; i > 1; i--){
while(head <= tail && q[head] - i >= n) head++; //如果不初始化,q[head]-i 就不能正确计算区间长度
while(head <= tail && sum[q[tail]] >= sum[i]) tail--;
q[++tail] = i;
if(i <= n + 1 && sum[q[head]] >= sum[i + n]) ans[i - 1] = 1;
}
当
还要注意的是