Codeforces 830A. Office Keys (背包dp+贪心) / (二分+贪心)

题目链接:

http://codeforces.com/problemset/problem/830/A

题意:

n个人,k个钥匙(n<=k),p表示这些人要到达的位置

给出n个人的位置以及钥匙的位置,问花时间最多的那个人用时最少是多少??

思路:

二分+贪心: 二分最少时间,需要对a,b位置数组排序,我们check函数只需要从左到右一个一个找过去,因为如果选后边的点,可能会使结果更差,假如当前这个人选后面的点,那可能会选中后面的人可以选的唯一的钥匙,不会使解更优。

check(40)的时候答案是false,是错误的,因为第一个人把第二个人可以唯一选的钥匙选上了。

复杂度是 O((n+k)*log(2e9))

dp+贪心:

dp[i][j]表示前i个人用前j把钥匙

转移: dp[i][j] = min(dp[i][j-1],max(dp[i-1][j-1],abs(a[i]-b[j])+abs(b[j]-p)));

dp[i][j-1]: 表示不选第 j 把钥匙

max(dp[i-1][j-1],abs(a[i]-b[j])+abs(b[j]-p)): 表示选第 j 把钥匙,就是考虑前 i-1 个人用前 j-1 把钥匙,第i个人用第j把钥匙,取最长的时间,因为答案要最长的人的时间

显然 取二者最小就是答案了  ----》 背包?

dp真奇妙啊!

代码一:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MS(a) memset(a,0,sizeof(a))
#define MP make_pair
#define PB push_back
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
inline ll read(){
    ll 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*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
//////////////////////////////////////////////////////////////////////////
const int maxn = 2e3+10;

ll dp[maxn][maxn],a[maxn],b[maxn];

int main(){
    int n,k,p;
    cin >> n >> k >> p;
    for(int i=1; i<=n; i++)
        cin >> a[i];
    for(int i=1; i<=k; i++)
        cin >> b[i];
    sort(a+1,a+1+n);
    sort(b+1,b+1+k);
    for(int i=0; i<=n; i++)
        for(int j=0; j<=k; j++)
            dp[i][j] = INFLL;
    for(int i=0; i<=k; i++) dp[0][i]=0;
    for(int i=1; i<=n; i++)
        for(int j=i; j<=k; j++){
            dp[i][j] = min(dp[i][j-1],max(dp[i-1][j-1],abs(a[i]-b[j])+abs(b[j]-p)));
        }
    cout << dp[n][k] << endl;

    return 0;
}

代码二:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MS(a) memset(a,0,sizeof(a))
#define MP make_pair
#define PB push_back
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
inline ll read(){
    ll 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*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
//////////////////////////////////////////////////////////////////////////
const int maxn = 2e3+10;

int n,k,pos;
ll a[maxn],b[maxn];
bool used[maxn];

bool check(ll x){
    int p = 0;
    for(int i=1; i<=n; i++){
        while(p<=k){
            p++;
            if(1LL*(abs(a[i]-b[p])+abs(b[p]-pos))<=x) break;
        }
        if(p > k) return false;
    }
    return true;
}

int main(){
    cin >> n >> k >> pos;
    for(int i=1; i<=n; i++)
        a[i] = read();
    for(int i=1; i<=k; i++)
        b[i] = read();
    sort(a+1,a+n+1); sort(b+1,b+k+1);

    ll L=0,R=2e9,ans=INFLL;
    while(L<=R){
        ll mid = (L+R)/2;
        if(check(mid)) ans=mid,R=mid-1;
        else L = mid+1;
    }
    cout << ans << endl;

    return 0;
}
时间: 2024-10-11 08:10:06

Codeforces 830A. Office Keys (背包dp+贪心) / (二分+贪心)的相关文章

【CodeForces】 830A Office Keys

传送门 codeforces luogu 题目描述 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. Onc

Codeforces VK Cup Finals #424 Div.1 A. Office Keys(DP)

显然是不可能交叉取钥匙的,于是把钥匙和人都按坐标排序就可以DP了 钥匙可以不被取,于是f[i][j]表示前i个钥匙被j个人拿的时间 f[i][j]=min(f[i-1][j],max(f[i-1][j-1],abs(b[i]-a[j])+abs(P-b[i])); #include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=1010,inf=2e9; int n,k,p; int a[maxn

Codeforces 589F F. Gourmet and Banquet(二分+贪心)

题目地址:http://codeforces.com/problemset/problem/589/F 思路:先贪心按照右端点值排序(先把对后面影响最小的菜吃掉),二分吃每道菜的时间即可. #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn=105; const int maxt=1e5+50

Codeforces Round #424 (Div. 2) D. Office Keys(dp)

题目链接:Codeforces Round #424 (Div. 2) D. Office Keys 题意: 在一条轴上有n个人,和m个钥匙,门在s位置. 现在每个人走单位距离需要单位时间. 每个钥匙只能被一个人拿. 求全部的人拿到钥匙并且走到门的最短时间. 题解: 显然没有交叉的情况,因为如果交叉的话可能不是最优解. 然后考虑dp[i][j]表示第i个人拿了第j把钥匙,然后 dp[i][j]=max(val(i,j),min(dp[i-1][i-1~j]))   val(i,j)表示第i个人拿

codeforces 148E Aragorn&#39;s Story 背包DP

Aragorn's Story Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/problem/148/E Description Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of enemies who

ZOJ 2109 FatMouse&#39; Trade (背包 dp + 贪心)

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1109 FatMouse prepared M pounds of cat food, ready to trade with the cats guarding the warehouse containing his favorite food, JavaBean. The warehouse has N rooms. The i-th room contains J

Codeforces 459E Pashmak and Graph(dp+贪心)

题目链接:Codeforces 459E Pashmak and Graph 题目大意:给定一张有向图,每条边有它的权值,要求选定一条路线,保证所经过的边权值严格递增,输出最长路径. 解题思路:将边按照权值排序,每次将相同权值的边同时加入,维护每个点作为终止点的最大长度即可. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 3

codeforces 289B - Polo the Penguin and Matrix 二分+dp

题意:给你一个序列,每一次可以对序列里面任意数+d 或者 -d 问你最少多少步能够使得数列里面所有的数相等 解题思路:从 1 - 10000 枚举这个数,二分找数列中小于等于它的最大的那个数,然后求前缀和以后刻意快速求出差值和的绝对值,差值和/d 就是我们所求数. 解题代码: 1 // File Name: 289b.cpp 2 // Author: darkdream 3 // Created Time: 2014年07月29日 星期二 22时33分11秒 4 5 #include<vecto

【bzoj4922】[Lydsy六月月赛]Karp-de-Chant Number 贪心+背包dp

题目描述 给出 $n$ 个括号序列,从中选出任意个并将它们按照任意顺序连接起来,求以这种方式得到匹配括号序列的最大长度. 输入 第一行包含一个正整数n(1<=n<=300),表示括号序列的个数. 接下来n行,每行一个长度在[1,300]之间的括号序列,仅由小括号构成. 输出 输出一行一个整数,即最大长度,注意你可以一个序列也不选,此时长度为0. 样例输入 3 ()) ((() )() 样例输出 10 题解 贪心+背包dp 首先对于一个括号序列,有用的只有:长度.消耗'('的数目.以及'('减去