D. Office Keys
分类:dp、二分、贪心
1.题意概述
- 一个坐标轴上有n个人,他们坐标分别为 a[1...n] ,而且有k把钥匙坐标分别在 b[1...k] ,现在办公室们在坐标为p的位置,每个人必须要拿到唯一一把钥匙进入办公室们,不同人之间不能共用,问你所有人进入办公室的最短时间是多少?
- 数据范围: 1 ≤ n ≤ 1 000,n ≤ k ≤ 2 000,1 ≤ p ≤ 109,1 ≤ ai ≤ 109,1 ≤ bj ≤ 109
2.解题思路
- 我们分别读入
a[1...n]
和
b[1...k]
,排序后观察,对于
ai≤aj
,
bk≤bm
,如果将这两把钥匙分配给这两个人,要分配方式最优只可能
ai→bk,aj→bm
,因为如果
ai→bm,aj→bk
,那么最大的花费时间是
max(|ai−bm|+|bm−p|,|aj−bk|+|bk−p|)
,显然小于前者
max(|ai−bk|+|bk−p|,|aj−bm|+|bm−p|)
,白话去理解就是离门最近的人去拿最远的钥匙是不可取的。
- 有了这个性质,我们容易发现这就符合线性dp的最优子结构啊,然后n和k的数据范围也很开心,复杂度 O(nk) !
- 当然根据这样分配性质,我们也完全可以考虑二分答案+贪心分配,每个人都去取离他最左侧钥匙就行!这样做复杂度 O(nklogm) 其中 m 是钥匙最大长度。
3.AC代码
dp代码
#include <bits/stdc++.h>
#define INF 0x7fffffff
#define maxn 100010
#define lson root << 1
#define rson root << 1 | 1
#define lent (t[root].r - t[root].l + 1)
#define lenl (t[lson].r - t[lson].l + 1)
#define lenr (t[rson].r - t[rson].l + 1)
#define N 1111
#define eps 1e-6
#define pi acos(-1.0)
#define e exp(1.0)
#define Close() ios::sync_with_stdio(0),cin.tie(0)
using namespace std;
const int mod = 1e9 + 7;
typedef long long ll;
typedef unsigned long long ull;
int a[N], b[N << 1], dp[N][N << 1];
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
long _begin_time = clock();
#endif
int n, k, p;
scanf("%d%d%d", &n, &k, &p);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (int i = 1; i <= k; i++)
scanf("%d", &b[i]);
sort(a + 1, a + n + 1);
sort(b + 1, b + k + 1);
dp[0][0] = 0;
for (int i = 1; i <= k; i++)
dp[0][i] = 0;
for (int i = 1; i <= n; i++)
{
dp[i][0] = INF;
for (int j = 1; j <= k; j++)
dp[i][j] = max(abs(a[i] - b[j]) + abs(b[j] - p), dp[i - 1][j - 1]);
for (int j = 1; j <= k; j++)
dp[i][j] = min(dp[i][j], dp[i][j - 1]);
}
printf("%d\n", dp[n][k]);
#ifndef ONLINE_JUDGE
long _end_time = clock();
printf("time = %ld ms.", _end_time - _begin_time);
#endif
return 0;
}
二分代码
#include <bits/stdc++.h>
#define INF 0x7fffffff
#define maxn 100010
#define lson root << 1
#define rson root << 1 | 1
#define lent (t[root].r - t[root].l + 1)
#define lenl (t[lson].r - t[lson].l + 1)
#define lenr (t[rson].r - t[rson].l + 1)
#define N 1111
#define eps 1e-6
#define pi acos(-1.0)
#define e exp(1.0)
#define Close() ios::sync_with_stdio(0),cin.tie(0)
using namespace std;
const int mod = 1e9 + 7;
typedef long long ll;
typedef unsigned long long ull;
int a[N], b[N << 1], n, k, p;
bool check(ll x)
{
int cnt = 0, next = 1;
for (int i = 1; i <= n; i++)
for (int j = next; j <= k; j++)
if (abs(a[i] - b[j]) + abs(b[j] - p) <= x)
{
next = j + 1;
cnt++;
break;
}
return cnt == n;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
long _begin_time = clock();
#endif
scanf("%d%d%d", &n, &k, &p);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (int i = 1; i <= k; i++)
scanf("%d", &b[i]);
sort(a + 1, a + n + 1);
sort(b + 1, b + k + 1);
ll l = -1, r = INF, ans = 0;
while (l <= r)
{
ll mid = l + r >> 1;
if (check(mid))
{
ans = mid;
r = mid - 1;
}
else
l = mid + 1;
}
printf("%I64d\n", ans);
#ifndef ONLINE_JUDGE
long _end_time = clock();
printf("time = %ld ms.", _end_time - _begin_time);
#endif
return 0;
}