bzoj1082: [SCOI2005]栅栏(二分答案搜索判断)

1082: [SCOI2005]栅栏

题目:传送门

题解:

   是不是一开始在想DP?本蒟蒻也是qwq,结果很nice的错了ORZ

   正解:二分+搜索

   我们可以先把两种木材都进行排序,那么如果需要的最大木材比可提供的最大木材还要大的话,那么可以直接舍弃这种需要的木材。

   然后就可以进入二分,如果当前可以做贡献的提供木材加起来都没有前mid块需要木材大的话,很明显当前mid不ok

   返回判断值再记录答案就好了,注意一些小细节的优化

代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<algorithm>
 6 typedef long long LL;
 7 using namespace std;
 8 bool flag;
 9 int n,m,mid;
10 int a[55],b[1005],bl[1005];
11 LL sa;
12 int sb[1005];
13 void dfs(int ak,int bk,int w)
14 {
15     if(bk==0)flag=1;
16     while(ak<=n && a[ak]<b[1]){w+=a[ak];ak++;}//当前木材比最小的需求值还要小,跳下一个木材
17     if(flag || ak>n)return;//如果已经合法或者没有符合要求的木材了就退出(因为已经排序过了啊)
18     if(w+sb[mid]>sa)return;//如果有贡献的提供木材加起来都没有前mid块需要木材大,肯定不ok
19     int t=ak,t1=ak,t2=bk,t3=w;
20     if(b[bk]==b[bk+1] && bk!=mid)t=bl[bk+1];//小剪枝,如果我当前需要的木块和上一块一样,直接跳到上一次使用过的木材
21     for(int i=t;i<=n;i++)
22         if(a[i]>=b[bk])
23         {
24             bl[bk]=i;a[i]-=b[bk];
25             bk--;
26             dfs(ak,bk,w);
27             ak=t1;bk=t2;w=t3;a[i]+=b[t2];
28         }
29 }
30 int main()
31 {
32     scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]);
33     scanf("%d",&m);for(int i=1;i<=m;i++)scanf("%d",&b[i]);
34     sort(a+1,a+n+1);sort(b+1,b+m+1);
35     while(b[m]>a[n])m--;//如果需要的最大木材比可提供的最大木材还要大,舍弃,直接m--
36     int tot=0;
37     for(int i=1;i<=n;i++)if(a[i]>b[1])a[++tot]=a[i];
38     n=tot;
39     for(int i=1;i<=n;i++)sa+=a[i];
40     for(int i=1;i<=m;i++)sb[i]=sb[i-1]+b[i];
41     int l=1,r=m,ans=0;
42     while(l<=r)
43     {
44         mid=(l+r)/2;
45         flag=0;
46         dfs(1,mid,0);
47         if(flag!=0)ans=mid,l=mid+1;
48         else r=mid-1;
49     }
50     printf("%d\n",ans);
51     return 0;
52 }

原文地址:https://www.cnblogs.com/CHerish_OI/p/8487949.html

时间: 2024-10-12 22:21:51

bzoj1082: [SCOI2005]栅栏(二分答案搜索判断)的相关文章

BZOJ1082: [SCOI2005]栅栏

1082: [SCOI2005]栅栏 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1906  Solved: 816[Submit][Status][Discuss] Description 农夫约翰打算建立一个栅栏将他的牧场给围起来,因此他需要一些特定规格的木材.于是农夫约翰到木材店购买木材.可是木材店老板说他这里只剩下少部分大规格的木板了.不过约翰可以购买这些木板,然后切割成他所需要的规格.而且约翰有一把神奇的锯子,用它来锯木板,不会产生任

BZOJ1082: [SCOI2005]栅栏 题解

题目大意: 有一些木材,可以没有浪费地将一根木材分成几块木板(比如长度为10的木板可以切成长度为8和2的两块木板).现在你希望得到一些长度的木板,问通过分割木材最多能得到几块想要的木板. 思路: 首先,长度短的木板一定比长度长的木板容易得到,因此若要得到最多的木板,它们必定是所有木板中最短的——可以对木板排序后二分答案(用k表示). 判断是否合法就用搜索,但数据有点大,要用到两个剪枝.一个是若有一根木材被切开后剩下的长度比最短的木板还短则将其累加入waste,当waste+前k块木板的长度和>木

【BZOJ 1082】[SCOI2005]栅栏 二分+dfs

对于最优解我们发现所有的最优解都可以是前多少多少个,那么我们就二分这个前多少多少个,然后用dfs去判解,我们发现在dfs的过程中如果不剪枝几乎必T,所以我们就需要一些有效的剪枝 I. 我们在枚举过程中每个数选什么是有前后顺序的,然而对于一些相同的数他们并没有顺序我们可以记录上个数的选择点,如果两数相同,那么就从上个数的选择点开始那么时间复杂度就从次方级别降到了组合数级别,是飞跃式的 II. 然后我们发现先对于枚举顺序与选择顺序的选择是玄学的,我们可以视为他们都没影响那么我们就可利用这个了,如果我

「二分答案 + 搜索」[HAOI2007]覆盖问题

[HAOI2007]覆盖问题 题目链接:[HAOI2007]覆盖问题 题目大意 给你\(n\)个坐标,再给你3个\(l \times l\)的矩阵,让你用这些矩阵去包含这些点,要求是将所有点都包含,我们要求\(l\)的最小值 题目题解 想到二分了,不过没想到怎么爆搜 看了下题解,妙啊妙啊,牛逼 每次二分一个 \(l\) 值作为我们想要的矩阵边长,然后由树的坐标我们可能可以找到比原平面直角坐标系更小的一个坐标系,我们在新的坐标系上进行操作就可以了,但怎么进行操作呢?我们如果想尽可能的缩小新坐标系的

字符串hash + 二分答案 - 求最长公共子串 --- poj 2774

Long Long Message Problem's Link:http://poj.org/problem?id=2774 Mean: 求两个字符串的最长公共子串的长度. analyse: 前面在学习后缀数组的时候已经做过一遍了,但是现在主攻字符串hash,再用字符串hash写一遍. 这题的思路是这样的: 1)取较短的串的长度作为high,然后二分答案(每次判断长度为mid=(low+high)>>1是否存在,如果存在就增加下界:不存在就缩小上界): 2)主要是对答案的判断(judge函数

【算法学习笔记】52.一道题的三种方法..二分答案、动态规划、计算几何 SJTU OJ 1250 BestSubsequence

---恢复内容开始--- 1250. BestSubsequence Description LL有n个妹子,他给妹子们编号排成一排.据说今天天气大好,LL要去春游了,他决定要选定至少F个妹子一起去玩. 为了让妹子们开心,他决定选连续一段的妹子们.然后LL有个特殊的癖好,他喜欢体重比较厉害一些的妹子. 那你可以帮LL选妹子吗,使得选出来的这些妹子的平均体重最大. Input Format 输入第一行两个整数,n和F. 接下来n行,每行一个整数,表示妹子的体重. 对前50%的数据:1<=n<=2

[luoguP1316] 丢瓶盖(二分答案)

传送门 二分答案再判断即可 ——代码 1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #define max(x, y) ((x) > (y) ? (x) : (y)) 5 #define N 1000001 6 7 int n, m, ans, maxn; 8 int a[N]; 9 10 inline int read() 11 { 12 int x = 0, f = 1;

BZOJ 1639: [Usaco2007 Mar]Monthly Expense 月度开支( 二分答案 )

直接二分答案然后判断. ----------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define rep( i , n ) for( int i = 0 ;  i < n ; ++i ) #define clr

【bzoj1082】 SCOI2005—栅栏

http://www.lydsy.com/JudgeOnline/problem.php?id=1082 (题目链接) 题意 给出m块木柴,以及n块木板,要求将m块木柴做木板,要求将木柴切割成与木板一样的长度,问最多可以做成几块木板. Solution 今日考题.乍一看,好像可以二分,然而并不会check,于是码了个贪心,10分mdzz.. 正解:二分+搜索. 每次二分答案mid后,对每块木板进行搜索,枚举用那根木柴去进行切割.没想到剪枝这么强大,这都可以搜过去.. 剪枝1:一开始将不符合条件的