这题不难,主要讲一下思维过程。
我们设
a[i]
a
[
i
]
为
i
i
的油量,为
i
i
到或当
i=n
i
=
n
时
n
n
到的路径长度。
我们先考虑一个方向。
如果
1
1
满足要求,应满足哪些条件?
a[1]+a[2]≥b[1]+b[2]
a
[
1
]
+
a
[
2
]
≥
b
[
1
]
+
b
[
2
]
a[1]+a[2]+a[3]≥b[1]+b[2]+b[3]
a
[
1
]
+
a
[
2
]
+
a
[
3
]
≥
b
[
1
]
+
b
[
2
]
+
b
[
3
]
...
.
.
.
变一下
a[1]−b[1]>=0
a
[
1
]
−
b
[
1
]
>=
0
a[1]−b[1]+a[2]−b[2]>=0
a
[
1
]
−
b
[
1
]
+
a
[
2
]
−
b
[
2
]
>=
0
a[1]−b[1]+a[2]−b[2]+a[3]−b[3]>=0
a
[
1
]
−
b
[
1
]
+
a
[
2
]
−
b
[
2
]
+
a
[
3
]
−
b
[
3
]
>=
0
...
.
.
.
设
v[i]=a[i]−b[i]
v
[
i
]
=
a
[
i
]
−
b
[
i
]
则
v[1]≥0
v
[
1
]
≥
0
v[1]+v[2]≥0
v
[
1
]
+
v
[
2
]
≥
0
v[1]+v[2]+v[3]≥0
v
[
1
]
+
v
[
2
]
+
v
[
3
]
≥
0
...
.
.
.
我们设
sum[i]=∑ij=1v[j]
s
u
m
[
i
]
=
∑
j
=
1
i
v
[
j
]
则若
i
i
满足要求,
sum[i+1]−sum[i−1]≥0
s
u
m
[
i
+
1
]
−
s
u
m
[
i
−
1
]
≥
0
sum[i+2]−sum[i−1]≥0
s
u
m
[
i
+
2
]
−
s
u
m
[
i
−
1
]
≥
0
...
.
.
.
我们不妨把
v
v
数组倍长一下。
则
对于最小值,单调队列求一下即可。
记得反过来再做一遍。
不小心MLE了一次QAQ
#include<bits/stdc++.h>
using namespace std;
const int N=2000005;
int n,head,tail,a[N],b[N],q[N];
long long v[N],ans[N];
bool flag[N];
signed main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i],&b[i]);
a[i+n]=a[i];
b[i+n]=b[i];
}
for(int i=1;i<=2*n;i++){
v[i]=v[i-1]+a[i]-b[i];
}
q[head=tail=1]=1;
for(int i=2;i<2*n;i++){
while(head<=tail&&q[head]<i-n+1){
head++;
}
while(head<=tail&&v[i]<=v[q[tail]]){
tail--;
}
q[++tail]=i;
if(i>=n){
ans[i-n+1]=v[q[head]];
}
}
for(int i=1;i<=n;i++){
if(ans[i]>=v[i-1]){
flag[i]=true;
}
}
int tmp=b[n];
for(int i=n;i>1;i--){
b[i]=b[i-1];
}
b[1]=tmp;
for(int i=1;i<=n/2;i++){
swap(a[i],a[n-i+1]);
swap(b[i],b[n-i+1]);
}
for(int i=1;i<=n;i++){
a[i+n]=a[i];
b[i+n]=b[i];
}
for(int i=1;i<=2*n;i++){
v[i]=v[i-1]+a[i]-b[i];
}
q[head=tail=1]=1;
for(int i=2;i<2*n;i++){
while(head<=tail&&q[head]<i-n+1){
head++;
}
while(head<=tail&&v[i]<=v[q[tail]]){
tail--;
}
q[++tail]=i;
if(i>=n){
ans[i-n+1]=v[q[head]];
}
}
for(int i=1;i<=n;i++){
if(ans[i]>=v[i-1]){
flag[n-i+1]=true;
}
}
for(int i=1;i<=n;i++){
puts(flag[i]?"TAK":"NIE");
}
return 0;
}