7 条题解
-
12
二分答案题目的特性:
-
答案一般具有单调性
-
有如下关键字:最短的最大,最小的最大,最大的最小等。
本题二分答案的主要思路就是对跳跃距离进行二分,
跳跃距离最小是1,最大是x。
因此对该区间二分,当我们选择mid这个距离进行跳跃,
如何设置检查函数?
枚举验证,看在当前这个距离下,是否可以移走不大于z的石头个数
如果可以,就说明这个距离没问题,否则不行。
需要注意题目说的是起点和终点之间有n个石头,
因此我们还需要人为加上 //x是终点到起点的距离
int x,y,z,l,r,mid,ans,a[50005]; //x是起点到终点距离,y是岩石个数,z是最多移走的个数。 bool check(int x) { int sum=0,now=0; for(int i=1;i<=y;i++) { if(a[i]-a[now]<x) sum++; else now=i; } if(sum<=z) return true; else return false; }
核心代码如上,其余就是二分答案的模板代码。
注意记得排序石块的距离。
并设置
然后 。二分即可
-
-
6
首先,这是一道二分题,初始化左端点0,右端点L;
#include <cstdio> using namespace std; int len,m,n,l,r,mid,ans,d[50005]; bool check(int x){ int lastpos=0,cnt=0; for(int i=1;i<=n;i++)d[i]-d[lastpos]<x?cnt++:lastpos=i; return d[n+1]-d[lastpos]>=x && cnt<=m;//因为最后一块不能移走,所以要单独考虑 } int main(){ scanf("%d%d%d",&len,&n,&m); for(int i=1;i<=n;i++)scanf("%d",&d[i]); d[n+1]=len,d[0]=0,l=1,r=len; while(l<=r){ mid=(l+r)/2; check(mid)?ans=mid,l=mid+1:r=mid-1; } printf("%d\n",ans); return 0; }
-
4
#include <iostream> using namespace std; int n, m, k, r, mid, ans; int a[500000000]; long long l; bool check(int x) { int last = 0; int sum = 0; for (int i = 1; i <= n; i++) { if (a[i] - last < x) { sum++; } else { last = a[i]; } if (sum > k) return false; } return true; } int main() { cin >> m >> n >> k; for (int i = 1; i <= n; i++) cin >> a[i]; a[n + 1] = m; l = 1; r = m; while (l <= r) { mid = (l + r) / 2; if (check(mid)) { ans=mid; l=mid+1; } else { r=mid-1; } } cout << ans << endl; return 0; }
-
1
二分答案,左端点是1,右端点是l,运用check函数判断是否能成立。
#include <iostream> using namespace std; int l,n,m,d[10000000]; bool check(int mid){ int sum=0,next=0; for(int i=1;i<=n;i++) if(d[i]-next<mid) sum++; else next=d[i]; return sum<=m; } int main(void){ cin>>l>>n>>m; for(int i=1;i<=n;i++) cin>>d[i]; int L=1,R=l,mid,ans; while(L<=R){ mid=(L+R)/2; if(check(mid)){ L=mid+1; ans=mid; } else R=mid-1; } cout<<ans; return 0; }
-
0
#include <iostream> using namespace std; int n, m, k, l, r, mid, ans; int a[50005]; bool check(int x) { int last = 0; int sum = 0; for (int i = 1; i <= n; i++) { if (a[i] - last < x) { sum++; } else { last = a[i]; } if (sum > k) return false; } return true; } int main() { cin >> m >> n >> k; for (int i = 1; i <= n; i++) cin >> a[i]; a[n + 1] = m; l = 1; r = m; while (l <= r) { mid = (l + r) / 2; if (check(mid)) { ans = mid; l = mid + 1; } else { r = mid - 1; } } cout << ans << endl; return 0; }
-
-3
hetao28428387 LV 9
P1409[普及~提高][NOIP2015提高组]跳石头
说明
一年一度的"跳石头"比赛又要开始了!
这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有N块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。
为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走M块岩石(不能移走起点和终点的岩石)。
输入格式
第一行包含三个整数L,N,M,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证L≥1且N≥M≥0。
接下来 N 行,每行一个整数,第i行的整数Di(0<Di<L),表示第i块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。
输出格式
一个整数,即最短跳跃距离的最大值。
样例
输入数据1
25 5 2 2 11 14 17 21
输出数据1
4
提示
输入输出样例1说明:将与起点距离为2和14的两个岩石移走后,最短的跳跃距离为4(从与起点距离17的岩石跳到距离21的岩石,或者从距离21的岩石跳到终点)。
另:对于20%的数据,0≤M≤N≤10。
对于50%的数据,0≤M≤N≤100。
对于100%的数据,0≤M≤N≤50,000,1≤L≤1,000,000,000 。
代码:
这是一道二分题,初始化左端点0,右端点L。
#include<cstdio> int b,c,d,e,f,g,h,a[50000]; bool check(int i){int j=0,k=0;for(int l=1;l<=d;l++){a[l]-a[j]<i?k++:j=l;}return a[d+1]-a[j]>=i&&k<=c;} int main(){ scanf("%d%d%d",&b,&d,&c); for(int l=1;l<=d;l++)scanf("%d",&a[l]); a[d+1]=b,a[0]=0,e=1,f=b; while(e<=f){g=(e+f)/2;check(g)?h=g,e=g+1:f=g-1;} printf("%d\n",h); return 0; }
代码已消毒,请放心食用。
-
-3
#include <iostream> #include <list> #define maxn 50005 const int inf = 0x7fffffff; using namespace std; int l, n, m; int dist[maxn]; bool check(int k); int main() { cin >> l >> n >> m; for (int i = 1; i <= n; i++) cin >> dist[i]; dist[++n] = l; int left = 0, right = 1000000005, mid; while (left < right) { mid = (left + right + 1) / 2; if (check(mid)) // 能否仅通过移去m块石头使所有跳跃距离≥mid left = mid; else right = mid - 1; } cout << left << endl; return 0; } bool check(int k) { int cnt = 0; int last = 0; for (int i = 1; i <= n; i++) { if (dist[i] - dist[last] < k) cnt++; else last = i; if (cnt > m) return false; } return true; }
- 1
信息
- ID
- 1409
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 6
- 标签
- 递交数
- 1065
- 已通过
- 365
- 上传者