我平时一般是每道题分开写博客的,但为什么这次两道题放在一起了呢?因为实在是太像了!但是它们是相似又相反的,在这好好分析对比一下。
1、P2678 跳石头
这道题是求最小值的最大值,画个图示如下:
如果判断mid符合题意,那么先把mid存到ans里,然后l = mid + 1,往右边找
如果不符合题意,r = mid - 1,往左边找
代码就长这样(说实话我也没想到我能一遍过
#include <cstdio>
#include <iostream>
#include <cmath>
#define MAXN 50005
using namespace std;
int len, n, m, ans;
int l, r, mid;
int a[MAXN];
bool judge()
{
int tot = 0;
int front, back;
front = 0; back = 1;
while(back <= n)
{
if(a[back] - a[front] < mid)
tot ++, back ++;
else
{
front = back;
back = front + 1;
}
}
//printf("ans IS %d\n", ans);
if(len - a[front] >= mid && tot <= m) return true;
else return false;
}
int main()
{
scanf("%d%d%d", &len, &n, &m);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
a[n + 1] = len;
l = 0;
r = len;
while(l <= r)
{
mid = (l + r) >> 1;
if(judge()) ans = mid, l = mid + 1;
else r = mid - 1;
}
printf("%d\n", ans);
return 0;
}
2、P3853路标设置
我第一眼看的时候想,这两题不是一样的嘛!就准备把上一题的代码交上去试试 (冲动是魔鬼 仔细看题发现不对
这题是求最大值的最小值,示意图长这样
和上一题比起来发现了啥? 符合和不符合关系颠倒了!
但关系颠倒了会有什么影响呢?看图可以知道:
如果判断mid符合题意,那么先把mid存到ans里,然后r = mid - 1,往左边找
如果不符合题意,l = mid + 1,往右边找!
这和刚刚往左往右变换边界的关系变反了!
这就很amazing
#include <cstdio>
#include <iostream>
#include <cmath>
#define MAXN 100005
using namespace std;
int len, n, k, ans;
int l, r, mid;
int a[MAXN];
bool judge()
{
int tot = 0;
for(int i = 2; i <= n; i ++)
{
if(a[i] - a[i-1] > mid)//需要增设路标
{
if((a[i] - a[i - 1]) % mid == 0) tot += (a[i] - a[i - 1]) / mid - 1;
else tot += (a[i] - a[i - 1]) / mid;
}
//printf("tot is %d\n", tot);
}
return tot <= k;
}
int main()
{
scanf("%d%d%d", &len, &n, &k);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
l = 0;
r = len;
while(l <= r)
{
mid = (l + r) >> 1;
if(judge()) ans = mid, r = mid - 1;
else l = mid + 1;
//printf("l is %d, r is %d\n", l, r);
}
printf("%d\n", ans);
return 0;
}
总结一下就是,二分非常套路:判断、变换边界即可
至于怎么变换边界需要按题目具体分析,不能一概而论!