Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem D (Codeforces 831D) - 贪心 - 二分答案 - 动态规划
There are n people and k keys on a straight line. Every person wants to get to the office which is located on the line as well. To do that, he needs to reach some point with a key, take the key and then go to the office. Once a key is taken by somebody, it couldn't be taken by anybody else.
You are to determine the minimum time needed for all n people to get to the office with keys. Assume that people move a unit distance per 1 second. If two people reach a key at the same time, only one of them can take the key. A person can pass through a point with a key without taking it.
The first line contains three integers n, k and p (1 ≤ n ≤ 1 000, n ≤ k ≤ 2 000, 1 ≤ p ≤ 109) — the number of people, the number of keys and the office location.
The second line contains n distinct integers a1, a2, ..., an (1 ≤ ai ≤ 109) — positions in which people are located initially. The positions are given in arbitrary order.
The third line contains k distinct integers b1, b2, ..., bk (1 ≤ bj ≤ 109) — positions of the keys. The positions are given in arbitrary order.
Note that there can't be more than one person or more than one key in the same point. A person and a key can be located in the same point.
Print the minimum time (in seconds) needed for all n to reach the office with keys.
2 4 50
20 100
60 10 40 80
50
1 2 10
11
15 7
7
In the first example the person located at point 20 should take the key located at point 40 and go with it to the office located at point 50. He spends 30 seconds. The person located at point 100 can take the key located at point 80 and go to the office with it. He spends 50 seconds. Thus, after 50 seconds everybody is in office with keys.
题目大意 一个走廊里有n个人和k个钥匙,办公室在位置p,假定每个人每秒走一米,问至少要到少时间才能使得所有人到达办公室(进入办公室必须要钥匙,并且拿到了钥匙就不能给别人)。
Solution 1 (Slower Binary Search)
题目要求最大值最小,十有八九都是二分答案,因此,求值问题被转化成判定问题,给定时间mid,判断是否能够使得所有人进入办公室。
首先可以把每个人可以拿钥匙的区间求出来,然后按左端点排一道序(因为就算先将人按位置排序,也不能保证区间的长度一样,即不能保证左端点的单调性),接着开始贪心,让每个人尽量拿靠左的钥匙(当然你按右端点排序,让每个人拿尽量靠右的钥匙也可以),中间判断一下是否可行。(如果你高兴的话还可以写二分匹配,当然由于覆盖的都是连续的区间,因此也没这个必要)所以,先要按钥匙的位置排一次序。
然后写这道题的时候发生了好玩的事情,第一次交上去Wrong Answer on test 8,然后我看错了Output和Answer,我还以为cf机子中毒,连续交了几次,最后恍然发现,看反了,内心是崩溃的,当发现把这道题A掉后,它的提交次数比Virtaul practise时提交的总次数还多。
另外注意一点,二分的左端点应从0开始,比如,只有一个人1把钥匙,人站在办公室门口,钥匙在办公室门口。
Code
/**
* Codeforces
* Problem#831D
* Accepted
* Time:15ms
* Memory:2100k
*/
#include <iostream>
#include <cstdio>
#include <ctime>
#include <cmath>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <stack>
#include <cassert>
#ifndef WIN32
#define Auto "%lld"
#else
#define Auto "%I64d"
#endif
using namespace std;
typedef bool boolean;
const signed int inf = (signed)((1u << ) - );
const signed long long llf = (signed long long)((1ull << ) - );
const double eps = 1e-;
const int binary_limit = ;
#define smin(a, b) a = min(a, b)
#define smax(a, b) a = max(a, b)
#define max3(a, b, c) max(a, max(b, c))
#define min3(a, b, c) min(a, min(b, c))
template<typename T>
inline boolean readInteger(T& u){
char x;
int aFlag = ;
while(!isdigit((x = getchar())) && x != '-' && x != -);
if(x == -) {
ungetc(x, stdin);
return false;
}
if(x == '-'){
x = getchar();
aFlag = -;
}
for(u = x - ''; isdigit((x = getchar())); u = (u << ) + (u << ) + x - '');
ungetc(x, stdin);
u *= aFlag;
return true;
} int n, m, p;
int *ps, *ks; inline void init() {
readInteger(n);
readInteger(m);
readInteger(p);
ps = new int[(n + )];
ks = new int[(m + )];
for(int i = ; i <= n; i++)
readInteger(ps[i]);
for(int i = ; i <= m; i++)
readInteger(ks[i]);
} pair<int, int>* ls;
boolean check(int mid) {
for(int i = ; i <= n; i++) {
int dis = abs(ps[i] - p);
if(dis > mid) return false;
dis = (mid - dis) >> ;
int l = ps[i], r = p;
if(l > r) swap(l, r);
l -= dis, r += dis;
ls[i] = pair<int, int>(l, r);
}
// cout << mid << " " << ls[1].first << " " << ls[1].second << endl;
sort(ls + , ls + n + );
int i, fin;
for(i = , fin = ; i <= n; i++, fin++) {
while(fin <= m && ks[fin] < ls[i].first) fin++;
if((ls[i].second < ks[fin]) || fin > m)
return false;
}
return true;
} inline void solve() {
sort(ks + , ks + m + );
// sort(ps + 1, ps + n + 1);
ls = new pair<int, int>[n + ];
int l = , r = 2e9;
while(l <= r) {
int mid = l + ((r - l) >> );
if(check(mid)) r = mid - ;
else l = mid + ;
}
printf("%d", r + );
} int main() {
init();
solve();
return ;
}
Binary Search (Slower)
Solution 2 (Faster Binary Search)
虽然可以O(nlogn)进行二分的check,但是有个更傻逼的贪心check可以做到线性。
就是从第一个钥匙开始for,找到第一个满足条件的钥匙(满足条件是指第一个人拿这个钥匙)给第一个人,第二个符合条件的钥匙给第二个人。。像这样安排下去,如果钥匙不够就说明不行,否则当前二分值可行。
Code
/**
* Codeforces
* Problem#831D
* Accepted
* Time: 15ms
* Memory: 12k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean;
const signed int inf = (signed)(~0u >> ); int n, m, p;
int *as, *bs; inline void init() {
scanf("%d%d%d", &n, &m, &p);
as = new int[(n + )];
bs = new int[(m + )];
for(int i = ; i <= n; i++)
scanf("%d", as + i);
for(int i = ; i <= m; i++)
scanf("%d", bs + i);
} boolean check(int mid) {
int j = ;
for(int i = ; i <= n; i++, j++) {
while(j <= m && abs(as[i] - bs[j]) + abs(bs[j] - p) > mid)
j++;
if(j > m)
return false;
}
return true;
} inline void solve() {
sort(as + , as + n + );
sort(bs + , bs + m + );
int l = , r = inf - ;
while(l <= r) {
int mid = l + ((r - l) >> );
// cerr << mid << endl;
if(check(mid)) r = mid - ;
else l = mid + ;
}
printf("%d", r + );
} int main() {
init();
solve();
return ;
}
Binary Search (Faster)
Solution 3 (dp)
仔细分析题目,可以发现当i < j,x < y时,第i个人去拿第y把钥匙肯定,第j个人去拿第x把钥匙肯定没有第i个人去拿第x把钥匙,第j个人去拿第y把钥匙更优。
所以有了两种设计状态的方法
1)用f[i][j]表示第i个人拿第j把钥匙最少消耗的最大时间。
转移从f[i - 1][i]到f[i - 1][j]取个最小值,然后和第i个人去拿第j把钥匙的时间取最大值。
但是这么做会T掉,所以考虑用一个变量维护最小值,不断更新即可。
注意f[i][j]的边界
。(虽然不注意就只是慢了点)
2)用f[i][j]表示考虑到第i把钥匙,已经有j个人拿到了钥匙的最少消耗的最大时间。
f[i][j]通过f[i - 1][j]或者f[i - 1][j - 1]转移。
我写的是第一种设计状态的dp做法。
Code
/**
* Codeforces
* Problem#831D
* Accepted
* Time: 15ms
* Memory: 7856k
*/
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <vector>
#include <bitset>
#ifdef WIN22
#define Auto "%I64d"
#else
#define Auto "%lld"
#endif
using namespace std;
typedef bool boolean;
#define ll int
#define smin(_a, _b) _a = min(_a, _b)
#define smax(_a, _b) _a = max(_a, _b)
const signed int inf = (signed) (~0u >> );
const signed ll llf = (signed ll) (~0ull >> ); template<typename T>
inline void readInteger(T& u) {
static char x;
while(!isdigit(x = getchar()));
for(u = x - ''; isdigit(x = getchar()); u = u * + x - '');
} template<typename T>
class Matrix {
public:
T* p;
int row;
int col;
Matrix():p(NULL) { }
Matrix(int row, int col):row(row), col(col) {
p = new T[(row * col)];
} T* operator [] (int pos) {
return p + (pos * col);
}
};
#define matset(a, i, s) memset(a.p, i, s * a.row * a.col) int n, m, s;
int *ps, *qs;
Matrix<ll> f; inline void init() {
readInteger(n);
readInteger(m);
readInteger(s);
ps = new int[(n + )];
qs = new int[(m + )];
f = Matrix<ll>(n + , m + );
matset(f, 0x3f, sizeof(ll));
for(int i = ; i <= n; i++)
readInteger(ps[i]);
for(int i = ; i <= m; i++)
readInteger(qs[i]);
} inline void solve() {
sort(ps + , ps + n + );
sort(qs + , qs + m + );
f[][] = ;
for(int i = ; i <= n; i++) {
ll minv = f[i - ][i - ];
for(int j = i; j <= m - n + i; j++) {
f[i][j] = max(minv, abs(ps[i] - qs[j]) + abs(qs[j] - s));
smin(minv, f[i - ][j]);
}
}
ll res = inf;
for(int i = n; i <= m; i++)
smin(res, f[n][i]);
printf("%d", res);
} int main() {
init();
solve();
return ;
}
Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem D (Codeforces 831D) - 贪心 - 二分答案 - 动态规划的更多相关文章
- Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem C (Codeforces 831C) - 暴力 - 二分法
Polycarp watched TV-show where k jury members one by one rated a participant by adding him a certain ...
- Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem F (Codeforces 831F) - 数论 - 暴力
题目传送门 传送门I 传送门II 传送门III 题目大意 求一个满足$d\sum_{i = 1}^{n} \left \lceil \frac{a_i}{d} \right \rceil - \sum ...
- Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem E (Codeforces 831E) - 线段树 - 树状数组
Vasily has a deck of cards consisting of n cards. There is an integer on each of the cards, this int ...
- Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) Problem E (Codeforces 828E) - 分块
Everyone knows that DNA strands consist of nucleotides. There are four types of nucleotides: "A ...
- Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem A - B
Array of integers is unimodal, if: it is strictly increasing in the beginning; after that it is cons ...
- Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) Problem D (Codeforces 828D) - 贪心
Arkady needs your help again! This time he decided to build his own high-speed Internet exchange poi ...
- Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) Problem C (Codeforces 828C) - 链表 - 并查集
Ivan had string s consisting of small English letters. However, his friend Julia decided to make fun ...
- Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals)
http://codeforces.com/contest/831 A. Unimodal Array time limit per test 1 second memory limit per te ...
- Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals)A,B,C
A:链接:http://codeforces.com/contest/831/problem/A 解题思路: 从前往后分别统计递增,相等,递减序列的长度,如果最后长度和原序列长度相等那么就输出yes: ...
随机推荐
- Cocos Creator 为Button添加事件的两种方法
Button添加事件 Button 目前只支持 Click 事件,即当用户点击并释放 Button 时才会触发相应的回调函数.通过脚本代码添加回调方法一这种方法添加的事件回调和使用编辑器添加的事件回调 ...
- cocos2d JS-(JavaScript) JavaScript 中的简单继承关系
JavaScript 语言本身没有提供类,没有其他语言的类继承机制,它的继承时通过对象的原型实现的,但这不能满足我们对 Cocos2d-JS 引擎的要求,所有类都直接或间接继承实现的. var Per ...
- 使用pycharm调试django项目
要使用pycharm调试django 打断点调试后台代码,首先要进行一下配置: 1.debug 配置 打开debug界面 2.选择python点+加号,然后选择python 3.名字debug,这个看 ...
- ASP.Net Core 2.2 MVC入门到基本使用系列 (三)(转)
本教程会对基本的.Net Core 进行一个大概的且不会太深入的讲解, 在您看完本系列之后, 能基本甚至熟练的使用.Net Core进行Web开发, 感受到.Net Core的魅力. 本教程知识点大体 ...
- MyBatis基础入门《十七》动态SQL
MyBatis基础入门<十七>动态SQL 描述: >> 完成多条件查询等逻辑实现 >> 用于实现动态SQL的元素主要有: > if > trim > ...
- leetcode insertionSortList 对链表进行插入排序
描述: Sort a linked list using insertion sort. 使用插入排序对一个链表进行排序 普通的插入排序,时间复杂度O(n^2) class Solution { pu ...
- [9]Windows内核情景分析 --- DPC
DPC不同APC,DPC的全名是'延迟过程调用'. DPC最初作用是设计为中断服务程序的一部分.因为每次触发中断,都会关中断,然后执行中断服务例程.由于关中断了,所以中断服务例程必须短小精悍,不能消耗 ...
- HTTP GET的VC三种方式
一.第一种方式(包装类的方式) a.在VC++添加类,选择typelib b.选择文件:C:\Windows\System32\winhttp.dll 选择到右边生成的类,最后点完成,即产生了一个CW ...
- Metasploit渗透技巧:后渗透Meterpreter代理
Metasploit是一个免费的.可下载的渗透测试框架,通过它可以很容易地获取.开发并对计算机软件漏洞实施攻击测试.它本身附带数百个已知软件漏洞的专业级漏洞攻击测试工具. 当H.D. Moore在20 ...
- 改装原生的dialog
改装 dialog 定制 View rootView = LayoutInflater.from(mContext). inflate(R.layout.nfc_tag_name_dialog, nu ...