传送门

题意:

  有 n 个数 (1 ~ n) 分给了三个人 a, b, c; 其中 a 有 k1 个, b 有 k2 个, c 有 k3 个。

  现在问最少需要多少操作,使得 a 中所有数 是 1 ~ n 的一个前缀;

  c 中所有数 是 1 ~ n 的一个后缀。 剩下的都在 b 手上。

  每次操作可以让一个人手上的一个数给另一个人。

解: 简单 DP ; 显然就是问你 把  1 ~ n 分成三段的最少花费。

  你把 第一个人 最初拥有的数, 所在的桶 定义为 0;

  第二个人的为1, 第三个人的为2。

  然后你就可以 DP 了;

  dp[ i ][ 0 ] 就代表, 你的 第一个人取 1 ~ i 的花费。

  dp[ i ][ 1 ] 就表示, 第一个人 拿了 1 ~ i 的前缀 1 ~ pos 部分, 第二个人拿了, 剩下的 pos ~ i 部分的最少花费。

  dp[ i ][ 2 ] 类似。 看代码的式子应该就懂了。

#include <bits/stdc++.h>
#define LL long long
#define rep(i, j, k) for(int i = j; i <= k; i++)
#define dep(i, j, k) for(int i = k; i >= j; i--)
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define mem(i, j) memset(i, j, sizeof(i))
#define pb push_back
using namespace std; const int N = 2e5 + ;
int A[N];
int dp[N][];
int main() { int a, b, c; scanf("%d %d %d", &a, &b, &c);
int n = a + b + c;
for(int i = ; i <= a; i++) {
int x; scanf("%d", &x); A[x] = ;
}
for(int i = ; i <= b; i++) {
int x; scanf("%d", &x); A[x] = ;
}
for(int i = ; i <= c; i++) {
int x; scanf("%d", &x); A[x] = ;
}
for(int i = ; i <= n; i++) {
dp[i][] = dp[i - ][] + (A[i] != ? : );
dp[i][] = min(dp[i - ][], dp[i - ][]) + (A[i] != ? : );
dp[i][] = min(dp[i - ][], min(dp[i - ][], dp[i - ][])) + (A[i] != ? : );
}
printf("%d\n", min(dp[n][], min(dp[n][], dp[n][])));
return ;
}

官方解, 思维 + 贪心。

  我们假设三个人的数编号为 1 2 3

  首先, 假设我们定了 L, R。 就是说, 1 ~ L 这一段是 第一个人的, L ~ R 这一段是第二个人的。

  R ~ n 这一段是第三个人的。 那么, 你若确定了 L, R。  那么你的 答案, 就是固定的。

  我们假设  cnt[ L ][ i ] 表示 1 ~ L 这一段 是 i 个人的数的个数。

  我们假设 1 ~ L 这一段为 L,   L ~ R 这一段为 M 。  R ~ n 这一段为 R

  那么答案就是 cnt[ L ][ 2 ] + cnt[ L ][ 3 ] + cnt[ M ][ 1 ] + cnt[ M ][ 3 ] + cnt[ R ][ 1] + cnt[ R ][ 2 ];

  对吧。 那现在, 要是我们确定了 R 这个点。 然后, L 应该在什么位置 才是最优的呢。

  假设R 确定了。 那么 cnt[ L ][ 3 ] + cnt[ M ][ 3 ] , cnt[ R ][ 1 ] , cnt[ R ][ 2 ] 全都确定了嘛。

  那么还差 cnt[ L ][ 2 ] 和, cnt[ M ][ 1 ] 没有确定嘛。 那你想要 这两个值 尽可能的小嘛。

  那么就是 你希望, 1 ~ L 这一段中 2 的数 的个数尽可能少, L ~ R 这一段中 1 的数的个数尽可能少。

  那也可以说成, 你 1 ~ L 这一段中, 1 的个数尽可能的多, 2的个数尽可能的少嘛。

  因为你 1 ~ L 中 1 的个数尽可能多的话呢, 你 L ~ R 这一段中 1 的个数就自然小了嘛。

  那不就是 cnt[ L ][ 1 ] - cnt[ L ][ 2 ] 最大的时候 的位置, 就是 L 的位置吗。

  那么, 我们枚举  R, 再维护一个 cnt[ L ][ 1 ] - cnt[ L ][ 2 ] 的最大值。

  就可以确定 R 在这个点时的  最小答案了。

  我们假设 cnt[ L ][ 1 ] - cnt[ L ][ 2 ] 的最大值为 ma

  那么我们现在 让 R ~ n 这一段为 R, 1 ~ R 这一段为 LL 。

  那么答案就是 cnt[ R ][ 1 ] + cnt[ R ][ 2 ] + cnt[ LL ][ 3 ] + cnt[ LL ][ 1 ] - ma;

  就是答案了。 cnt[ LL ][ 1 ]  -  ma。  这一段代表的东西就是。

  你 ma 这个值是在最优的 L 处取得的嘛。

  那就是, 1 ~ R 这一段的所有的 1 减去,你 1 ~ L 这一段的不需要动的1嘛 。

  那得到的就是 L ~ R 这一段 1 的个数。

  再加上 你 1 ~ L 这一段的 2 的个数嘛。  那就刚好是 前面的 cnt[ L ][ 2 ] + cnt[ M ][ 1 ]。

  

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 2e5 + ;
int pos[N];
int cntR[];
int cntL[];
int main() {
int a, b, c; scanf("%d %d %d", &a, &b, &c);
int n = a + b + c;
for(int i = ; i <= a; i++) {
int x; scanf("%d", &x);
pos[x] = ;
}
for(int i = ; i <= b; i++) {
int x; scanf("%d", &x);
pos[x] = ;
}
for(int i = ; i <= c; i++) {
int x; scanf("%d", &x);
pos[x] = ;
}
for(int i = ; i <= n; i++) {
cntR[pos[i]]++;
}
/// 整段都是 3 的。
int ans = cntR[] + cntR[];
int ma = ;
for(int i = ; i <= n; i++) {
cntL[pos[i]]++;
cntR[pos[i]]--;
ma = max(ma, cntL[] - cntL[]);
int tmp = cntR[] + cntR[] + cntL[] + cntL[] - ma;
ans = min(ans, tmp);
}
printf("%d\n", ans);
return ;
}

  

E. The Contest ( 简单DP || 思维 + 贪心)的更多相关文章

  1. hdu 1257 && hdu 1789(简单DP或贪心)

    第一题;http://acm.hdu.edu.cn/showproblem.php?pid=1257 贪心与dp傻傻分不清楚,把每一个系统的最小值存起来比较 #include<cstdio> ...

  2. codeforce1029B B. Creating the Contest(简单dp,简单版单调栈)

    B. Creating the Contest time limit per test 1 second memory limit per test 256 megabytes input stand ...

  3. codeforces Gym 100500H A. Potion of Immortality 简单DP

    Problem H. ICPC QuestTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100500/a ...

  4. 『简单dp测试题解』

    这一次组织了一场\(dp\)的专项考试,出了好几道经典的简单\(dp\)套路题,特开一篇博客写一下题解. Tower(双向dp) Description 信大家都写过数字三角形问题,题目很简单求最大化 ...

  5. luoguP1281 书的复制 DP,贪心

    luoguP1281 书的复制 链接 https://www.luogu.org/problemnew/show/P1281 思路 简单dp,输出方案. 很明显dp记录路径对不对? 恭喜你死了. 求出 ...

  6. Codeforces Round #302 (Div. 2) C. Writing Code 简单dp

    C. Writing Code Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/544/prob ...

  7. 洛谷 - P1004 - 方格取数 - 简单dp

    https://www.luogu.org/problemnew/show/P1004 这道题分类到简单dp但是感觉一点都不简单……这种做两次的dp真的不是很懂怎么写.假如是贪心做两次,感觉又不能证明 ...

  8. HDU 5375 Gray code (简单dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5375 题面: Gray code Time Limit: 2000/1000 MS (Java/Oth ...

  9. 4.15 每周作业 —— 简单DP

    免费馅饼 Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) Total Submissi ...

随机推荐

  1. STM32之ADC实例(基于DMA方式)

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/zouleideboke/article/details/75112224 ADC简介: ADC(An ...

  2. k8s系列0--Kubernetes基础知识

    Kubernetes介绍 参考:Kubernetes核心组件解析 Pod是k8s的最小调度单元 每个pod有独立的IP,但是pod的IP是不可靠的,重新调度pod就会改变IP,service概念就是为 ...

  3. Django 中 app_name (应用命名空间) 和 namespace (实例命名空间) 的区别

    转自:https://www.jianshu.com/p/404500a0408a 补充理解: 先把官网上对应用命名空间(app_name)和实例命名空间(namespace)的解释贴上: app_n ...

  4. jacascript Date 学习

    前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! Date dateObject.getDate();  返回一个月中的某一天(1-31) dateObje ...

  5. RestControllerAdvice,ControllerAdvice

    1.切记@RestControllerAdvice 和 @ControllerAdvice 不能放在common里,会不生效,还会引起子项目的全局异常失败. 所以这2个还是放在各自的子项目里去处理.一 ...

  6. Python中的内存管理机制

    Python是如何进行内存管理的 python引用了一个内存池(memory pool)机制,即pymalloc机制,用于管理对小块内存的申请和释放 1.介绍 python和其他高级语言一样,会进行自 ...

  7. 详解为什么设置overflow为hidden可以清除浮动带来的影响

    1.问题起源 在平时的业务开发写CSS中,为了满足页面布局,元素的浮动特性我们用的不能再多了.使用浮动的确能够解决一些布局问题,但是也带了一些副作用影响,比如,父元素高度塌陷,我们有好几种可以清除浮动 ...

  8. 正则限制input负数输入

    //直接在input标签内加入下面两个事件处理程序即可 onkeyup="this.value=this.value.replace(/\D|^0/g,'')" onafterpa ...

  9. php使用播放插件播放m3u8,mp4,flv格式的视频

    一.这里我主要是播放m3u8的视频,有两款比较好的插件,swise和ckpalyer,我介绍的是ckplayer,这是在pc端播放的,并且是需要flash支持的,不过现在的最新浏览器都是默认安装的 二 ...

  10. 《python解释器源码剖析》第12章--python虚拟机中的函数机制

    12.0 序 函数是任何一门编程语言都具备的基本元素,它可以将多个动作组合起来,一个函数代表了一系列的动作.当然在调用函数时,会干什么来着.对,要在运行时栈中创建栈帧,用于函数的执行. 在python ...