codeforces732D 二分加贪心。。
啊,不好意思。。这个题窝也不会,看了网上的题解做的。。
先说一下题意。。
你要考试了。。然后你有n天的时间准备以及进行考试
并且,每一天。。要么你花一天时间去考一门(每天只能考一门),要么花一天时间休息,要么花一天时间复习。。
然后给你一个考试安排的序列(值为考试科目编号,值为零说明今天不能考试),给你一个每门考试至少要复习的时长的序列。。
然后问你最短多长时间你能顺利考完试。。不能考完就输出-1
题意:
给出一串数字,代表了第i天能够进行哪场考试,如果为0就不能考试,每天只能考一场。一共要考m场试,一个序列a[i],每门科目要a[i]的复习时间,所以问最快第几天能够考完所有科目。
题目连接 http://codeforces.com/problemset/problem/732/D
首先我们看到这个题。。md。。有种首尾不能相顾的感觉。。
但是呢,这个题很明显是让我们去找一个符合条件的,最小的值,这不就是二分的定义么。。
而且这个题很明显地有一个性质。。那就是时间越长你就越容易通过所有考试,时间越短当然也就越难通过
这是一个单调的性质。。
但是一开始并没有看出来。。。
比如说001230102,1和2都只需要1天时间复习,科目3需要4天时间复习
如果我们采用先安排最早考试的场次先考。。那么我们肯定是先去考1和2这两场了。。
然后我们就发现了。。如果你这么搞。。科目3铁定爆炸。。,我们其实可以选择靠后的1,2两场
如果你选了靠后的1,2如果后面紧接一个4,那还是爆炸了。。说不定把前面全排空了才来得及复习4,
而且你不确定排空到哪里。。我感觉应该是依赖于后续状态的。。
现在这么考虑的话。。应该有两个难点。。第一不知道后面的情况。。现在的决策就不一定正确。。
第二我们不知道应该按照何种顺序去考虑,或者是进行dp
//第一解决不知道后面的情况。。我们可以用dfs
我先在的想法是每个有编号的节点之间都连一条边。。然后中间所隔0的个数就可以当成这条边的权值
然后按照这条链去dfs一下?
//第二解决何种顺序。。我们强行定义一个顺序解决。。
dfs:我们按照考试的顺序去判断。。强行定一个1~m的顺序。。如果这1~m门课都考完了,这事不就办成了么。。
但是其实这样的话。。如果我们从科目k的若干考试时间选一个, 然后从这个时间往前,我们需要a[k]的考试
复习时间。。如果你这个时间往前未被使用的时间大于a[k](这里埋了一个坑,判断哪些时间未被使用)
我们就需要作出决定,我们要用这些未用时间的哪些天数来凑出一个a[k]的复习时间呢,
因为我们知道。。你选择不同的那些天。。可能会把一些本来考试的时间用来复习,并且是用来复习你这一科
那你后面搜索的状态集合就肯定会受你这个得影响。。但是没关系。。我们要跑遍所有集合。。
如果我们要进行如此的状态转移。。那我们还要维护一个vis[maxn]的状态。。
然后如果我们想从终态往上推的话。。首先终态是上完这m门课。。时间是m门中考试最晚的一门的考试时间
那么我们还要构造终态的vis[maxn]数组。。你如果按照科目编号状态转移。。中间很可能会空很多没有用的
天数。。对于这种情况我们需要去构造一下?但是这样枚举的话不就又成了dfs了?而且假如你能很快地构造出
dfs的叶子节点。。那么我们如何去递推他的父亲呢。。
那么我们要找n-1门课。。他的下层叶子节点假设全tm搞出来了。。那我也不知道怎么搞一个策略(可能是贪心的)
确定出来我要找哪个叶子节点,找到了这个叶子节点之后如何递推到他的父亲节点。。(枚举他的父亲,当然知道它的父亲是谁)
然后我们发现知道了叶子节点,如果他有多个可选择的n-1...我们还是不能确定地选出哪个n-1..虽然知道用了。。但是不知道是用来
复习了还是用来考试了。。考试就不能瞎调度了。。
想到这里我觉得可以分两个vis,vis1标记考试,vis2标记复习,但是你这样搞不就不用回溯了么。。也就是说只能是dfs从顶向下(其实顺序根本无所谓)跑出来的
直接去标记最晚最小者是答案。。大暴力啊。。能跑完么。。
所以说。。这么定义状态不行。。毛线的关系都没有。。放弃乱搞吧还是。。(hahahaha
===
其实这个题首要解决的问题有俩。。第一给你一个时间n你怎么去判它是合法的。。第二在判断合法的情况下,我们如何选择最小的
主要是第一个问题怎么解决。。
我们来分析第一个样例
7 2
0 1 0 2 1 0 2
1 2
首先我们知道这个答案是5,最短5天
5是一个合法的答案,如果我们按照先满足考试早的顺序来,先满足1,那2就肯定满足不了了。。然后5就不合法了
那么我们按照考试最晚的顺序来。。先满足后面那个1,那你要从后面四天选一天,显然第四天不能选,选了就gg,因为只要有一门没考完,这个事就没办好
然后我们可以选第三天,然后第4天的考试我们可以选。。因为第三天用过了,我们选1,2两天复习
然后我们也可以选第二天,然后第4天的考试我们可以选1,3两天复习
然后我们也可以选第一天,然后第4天的考试我们可以选择2,3两天复习
8 3
1 2 3 0 2 0 1 2
1 1 2
我先在的想法是贪心地从后往前取,然后贪心地先取离自己最近的零
假如上面的这个例子里面,我们后面的1,2如果不取离自己最近的零,那我们就可以去
前面的零或者是和自己编号一样的来复习,因为你现在决定考这个科目较晚的一场,那么我们就可以把较早的那场用来复习,或者看成是0也没有关系
所以可以取前面的1,2但是这样的话3就gg了。。既然我们可以取前面的1,2那么他们就可以看成是0,既然是0,那么我们完全可以交换0的位置,交换完全
不受影响,所以我们把前面这两个0和后面那两个没用过的零换一下,这样3前面有两个0,条件也满足了。。
10 3
0 2 0 1 0 0 1 2 3 2
1 1 4
从第10位判合法性。。先不要着急判最短,判合法即可
先满足最后一个2,后面的0和2就都变成0,随便取一个
假设取第五位的0,然后我们考虑3,从前面的0取4个,乍看不够是吧,因为5用过了
但是别忘了前面的2都变成0了,然后3取2,3,6,8的0,然后我们再考虑1 。。
1可以取第一位的0 。。然后就满足了
10 3
0 2 0 1 0 0 1 2 3 2
1 3 4
首先考虑最后一个2,考虑5,6,8三个0
然后对于3,考虑1,2,3三个0,woc零不够了。。
那说明没得交换了。。然后就gg
10 3
0 2 0 1 0 0 1 2 3 2
1 2 4
对于最后一个2,考虑6,8两个0
然后对于3取,1,2,3,5这四个零
然后对于1,后面的那个1就变成0了,取上
然后条件就满足了
11 3
0 0 2 0 1 0 0 1 2 3 2
1 2 4
根据前面的分析。。现在应该很熟练了吧 = =
所以说一旦我们每次所需的在自己前面位置的零的个数足够,如果是
因为0的位置取得不一样而导致某个考试不能完成,即复习内容不对
那因为都是0嘛,所以我们可以xjb交换满足条件。。 所以我们看了若干组数据才明白。。我们一旦把一些数据都搞成零以后,那么这些零就可以随便交换
我们就不要担心,到底要取哪些天用来复习,我们不用关心取这些零的哪些位置,而是只考虑个数就可以
所以说我们只考虑维护当前可用个数就能判断出来这组数据合不合法
(我这个其实不算是贪心证明,但是这是一种思想)
(多看数据,多试方法,多发现基本事实) 其实还是有点不清楚。。毕竟贪心很难得嘛。。或者我们可以这么想,当我们固定了时间之后,我们只需要判这个数据最宽松的做法
合不合法就行,你又不用判最短的。。这样你就把最短这一维去掉了。。所以说考试时间越晚我们越容易准备对吧。。(直觉上)
所以说我们先满足这个宽松的条件,然后只要满足就好啦,找到一组可行解能判断你合法就好啦,我管你条件是宽松还是紧张,这个其实
有点类似于放缩的思想。。(最优解不好找我们先想办法找最好满足的可行解) 而且这个东西关键在于从后往前。。因为这个时间确定了之后就可以从后往前
从前往后,一方面你过早地做了决定不好,你不知道后面的情况。。然后你往后走了一个位置
这个位置当然也是依赖后面的位置。。那就一直往后咯,我们需要找一个确定态。。那么好了
我直接找最后不就完事了么。。,然后我们从后往前考虑不就好了么。。
这个一条链的。。我们就别递归了吧。。浪费时间。。直接从后往前回溯得了 咳。。费了老大劲了才想出一个如何判合法的方法。。
这个思维的惯性不好。。,往后依赖了一步就懵逼了,继续往后依赖啊,只要到结尾不就好了么。。
然后我们从结尾往前就好了啊。。 找出判合法之后,然后我们发现答案有二分的性质,然后我们就二分答案,根据判合法函数找最小的满足条件的答案
下面上代码吧。。
其实这个题的贪心策略是:首先我们希望每门课的考试时间越晚越好,然后就是先复习最早开始的考试。
我们后面再分析这个贪心的策略
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
int n,m;
const int maxn=1e5+;
int d[maxn],a[maxn];
bool vis[maxn]; bool yes(int n){
memset(vis,,sizeof(vis));
int cur=n;
register int i;
for(i=n;i>=;--i){
//--写成了++
if(cur>i-) cur=i-;
if(d[i]&&!vis[d[i]]&&a[d[i]]<=cur){
//把d[i]!=0漏了。。
//前面算的时候肯定把当前这天当成资源天数了
//所以现在算的时候,今天用来考试
//要减去一天
cur--;
vis[d[i]]=true;
cur-=a[d[i]];
}
}
for(i=;i<=m;++i){
if(!vis[i]) return false;
//把i写成m了。。
}
return true;
}
int main(){
scanf("%d%d",&n,&m);
register int i;
for(i=;i<=n;++i){
scanf("%d",d+i);
}
for(i=;i<=m;++i){
scanf("%d",a+i);
}
int left=,right=n,mid;
while(left<=right){
mid=(left+right)>>;
// printf("mid:%d yes:%d\n",mid,yes(mid));
if(yes(mid)) right=mid-;
else left=mid+;
}
//left right写反了。。
int ans;
if(left>n){
//no anwser
printf("-1\n");
}
else{
if(!yes(right)){
right++;//ans is the next
}
printf("%d\n",right);
}
return ;
}
codeforces732D 二分加贪心。。的更多相关文章
- hdu 4004 (二分加贪心) 青蛙过河
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4004 题目意思是青蛙要过河,现在给你河的宽度,河中石头的个数(青蛙要从石头上跳过河,这些石头都是在垂 ...
- CodeForces - 363D --二分和贪心
题目:CodeForces - 363D 题意:给定n个学生,其中每个学生都有各自的私己钱,并且自己的私己钱只能用在自己买自行车,不能给别人. 给定m个自行车,每个自行车都有一个价格. 给定公有财产a ...
- 【BZOJ1816】[CQOI2010]扑克牌(二分,贪心)
[BZOJ1816][CQOI2010]扑克牌(二分,贪心) 题面 BZOJ 题解 看了一眼这题,怎么这么眼熟?woc,原来\(xzy\)的题目是搬的这道啊... 行,反正我考的时候也切了,这数据范围 ...
- Luogu 1084 NOIP2012 疫情控制 (二分,贪心,倍增)
Luogu 1084 NOIP2012 疫情控制 (二分,贪心,倍增) Description H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树, 1 号城市是首都, 也是 ...
- hdu 1598 (并查集加贪心) 速度与激情
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1598 一道带有贪心思想的并查集 所以说像二分,贪心这类基础的要掌握的很扎实才行. 用结构体数组储存公 ...
- POJ-2018 Best Cow Fences(二分加DP)
Best Cow Fences Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 10174 Accepted: 3294 Desc ...
- BZOJ_2196_[Usaco2011 Mar]Brownie Slicing_二分答案+贪心
BZOJ_2196_[Usaco2011 Mar]Brownie Slicing_二分答案+贪心 Description Bessie烘焙了一块巧克力蛋糕.这块蛋糕是由R*C(1 <= R,C ...
- 洛谷3933 Chtholly Nota Seniorious 二分答案+贪心
题目链接 题意 给你一个N*M的矩阵 (N,M <=2000) 把他分成两部分 使两部分的极差较大的一个最小 求这个最小值.然后分矩阵的要求是:每个部分内部的方块之间,可以通过上下左右相互到 ...
- BZOJ5321 JXOI2017加法(二分答案+贪心+堆+树状数组)
二分答案后得到每个位置需要被加的次数.考虑贪心.从左到右考虑每个位置,将以该位置为左端点的区间按右端点从大到小加进堆.看该位置还需要被加多少次,如果不需要加了就不管,否则取堆顶区间将其选择,BIT实现 ...
随机推荐
- MVC利用Routing实现多域名绑定一个站点、二级域名以及二级域名注册Area
最近有这么个需求:在一个站点上绑定多个域名,每个域名进去后都要进入不同的页面.实现了这个功能以后,对于有多个域名,且有虚拟空间,但是虚拟空间却只匹配有一个站点的用户来说,可以节省很多小钱钱. 很久以前 ...
- 百度地图代码API
百度地图代码API: http://api.map.baidu.com/lbsapi/creatmap/index.html
- 交叉编译php5,、nginx、squid方法
本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 交叉编译php5 软件版本:php-5.4.27 依赖库:zlib,libxml2 交叉编译器:arm-hisi ...
- RecContentType有哪些
HTML 页面text/javascript `type="text/javascript"` 是比较老的写法IETF 推荐的是 `type="application ...
- 小白科普之JavaScript的BOM模型
一.什么是BOM 1. BOM是browser object model的缩写,简称浏览器对象模型: 2. BOM提供了独立于内容而与浏览器窗口进行交互的对象,描述了与浏览器进行交互的方法和接口: 3 ...
- IOS 页面之间的跳转
1.UINavigationController popToViewController 对应popViewControllerAnimated: 也可以使用: [self.navigationCon ...
- xcode6 使用MJRefresh
1. MJRefreshConst.m 里面 会报错: unknown type 'NSString'... 原因: xcode6 取消.pch文件, 所以没有导入 foundation和uikit ...
- ZOJ3741 状压DP Eternal Reality
E - Eternal Reality Time Limit:2000MS Memory Limit:65536KB 64bit IO Format:%lld & %llu S ...
- Meta Programming
[本文链接] http://www.cnblogs.com/hellogiser/p/meta-programming.html [分析] Template Mataprogram,中文叫模板元编程. ...
- 【转】实战 SSH 端口转发
本文转自:http://www.ibm.com/developerworks/cn/linux/l-cn-sshforward/index.html,至于有什么用,懂的懂! 实战 SSH 端口转发 通 ...