二分+dp:[ARC120E] 1D Party

本文搬运自本人高中时期CSDN博客,若图片加载不出来,可到原文查看:https://blog.csdn.net/zhangtingxiqwq/article/details/134754875

https://www.luogu.com.cn/problem/AT_arc120_e

考虑二分时间,然后设 dp(i,0)dp(i,0) 表示第 ii 个人开头往左走,掉头后剩余步数。 dp(i,1)dp(i,1) 表示第 ii 个人先往右走,最多走多少步就有掉头。

然后在纸上画一画就是小学的相遇问题,直接转移即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include<bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stdout, ##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
//#define int long long
inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||
ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
#define fi first
#define se second
//srand(time(0));
#define N 200010
//#define M
//#define mo
void Mn(int &a, int b) {
if(a == -1) a=b; else a=max(a, b);
}
int n, m, i, j, k, T;
int d[N], dp[N][2], a[N], l ,r, mid;

bool check(int t) {
memset(dp, -1, sizeof(dp));
dp[1][1]=t;
for(i=2; i<=n; ++i) {
if(dp[i-1][1]!=-1) {
k=dp[i-1][1];
if(k*2>=d[i]) Mn(dp[i][0], t-d[i]/2);
if(k-d[i]/2>=0) Mn(dp[i][1], k-d[i]/2);
}
if(dp[i-1][0]!=-1) {
k=dp[i-1][0];
if(k*2>=d[i]) Mn(dp[i][0], k-d[i]/2);
if(k-d[i]/2>=0) Mn(dp[i][1], k-d[i]/2);
}
}
return dp[n][0]!=-1 || dp[n][1]!=-1;
}

signed main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
// T=read();
// while(T--) {
//
// }
n=read();
for(i=1; i<=n; ++i) a[i]=read();
for(i=2; i<=n; ++i) d[i]=a[i]-a[i-1];
l=1; r=1e18;
while(l<r) {
mid=(l+r)>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
printf("%lld", l);
return 0;
}