第二题不会贪太菜了。贪心策略:如果本次任务和下次有重合那么选择在重合部分就可以一次完成两个任务。根据依次所以不断考虑区间每次选择区间交集知道下一个区间和现在位置没有交集。判断一下在现在为止的左边还是右边。在左边就从交集区间左边出发右边同理。可以看出两个区间无论相差奇数个还是偶数个步数都是相通的(要么全是两部要么一个一步其他两部)但是位置是不同的,(偶数个走偶数部刚好到区间,奇数个有可能刚好到区间或者过区间一个)
这是第一个点:如果走到下一个区间有奇数个我是走奇数部还是走偶数部。看下下一个区间,如果下下一个区间和下一个区间同方向,当然
走偶数部,不然就走奇数部。但是不用判断的如此麻烦,由于步数是相通的,我们只要记录位置的可能范围(这里觉得大佬的思路太巨了)就可以了。
第二个坑点:如果下一个区间长度为1,即使下一个区间和下下一个区间同一边。举个例子,假如我在7,9。下一个区间是5,6.下下一个区间是2,3在6,7中间是奇数部,但是一次走两步明显更优。如果从7走到6走一次走两步,走到3就只用两次,如果一次走一步,那么一共要走三步。但是如果下一个区间是6,那么就不能走两步了,不然就会跨过区间。所以区间为1要特盘。
这个放下大老代码区间处理好简洁思路也清晰太强了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{
int L, R;
bool operator < (const node &b) const{
return R == b.R ? L > b.L : R < b.R;
}
};
vector<node> a;
int main()
{
int T, n; scanf("%d", &T);
while(T--){
scanf("%d", &n);
a.resize(n);
for(int i = 0; i < n; i++){
scanf("%d %d", &a[i].L, &a[i].R);
}
int L = a[0].L, R = a[0].R, ans = 0;
for(int i = 1; i < n; i++){
int l = max(L, a[i].L);
int r = min(R, a[i].R);
if(l <= r){
L = l, R = r;
continue;
} else {
if(a[i].L == a[i].R){
ans += min((abs(a[i].L - L) + 1)/2, (abs(a[i].L - R) + 1)/2);
L = R = a[i].L;
}else if(a[i].R < L){
if((L - a[i].R) & 1){
ans += (L - a[i].R + 1) / 2;
L = a[i].R - 1;
R = a[i].R;
}else{
ans += (L - a[i].R + 1) / 2;
L = a[i].R;
R = a[i].R;
}
}else{ // R < a[i].L
if((a[i].L - R) & 1){
ans += (a[i].L - R + 1) / 2;
L = a[i].L;
R = a[i].L + 1;
}else{
ans += (a[i].L - R + 1) / 2;
L = a[i].L;
R = a[i].L;
}
}
}
}
printf("%d\n", ans);
}
return 0;
}