题目
A - Robot Cleaner
题意:给定n × m的区间,然后给定机器人和目标的坐标,然后机器人起初往右下方走,碰到墙壁就会改变方向,类似于折射,然后问在最短走几步能移动到到目标的行或者是列。
思路:模拟,可以分为两个方向进行讨论,水平和垂直方向,如果目标在某一个方向的正方向的话,那么最短距离就是这个方向的距离差,否则就是(n - x) + (m - y),其实这个也不难理解,看看所给的图找找规律就好。
AC code
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n, m, ex, ey, bx, by, d;
int ans = 0x3f3f3f3f;
int main()
{
int t;
cin >> t;
while(t -- )
{
ans = 0x3f3f3f3f;
cin >> n >> m >> bx >> by >> ex >> ey;
if(ex == bx || ey == by) puts("0");
else
{
if(ex < bx)
{
int x = (n - ex) + (n - bx);
ans = min(ans, x);
}
else
if(ex > bx)
{
ans = min(ans, (ex - bx));
}
if(ey < by)
{
int x = (m - ey) + (m - by);
ans = min(x, ans);
}
else
if(ey > by)
{
ans = min(ans, ey - by);
}
cout << ans << endl;
}
}
return 0;
}
B - Game on Ranges
题意:Alice 选择一个区间,然后让Bob来选择一个数,比如Alice选择一个1-5的区间,Bob选择3,那么就会分成两个小区间1 - 2和4 - 5,或者是选择4,那么只剩下1 - 3和5 - 5两个区间,现在给你Alice选择的区间,然后让你写出Bob在Alice所给的区间种选择的哪个数,起初的区间是1 ~ n。
思路:模拟,可以将区间根据区间长度来进行升序排序,从最小的开始处理,区间种肯定存在着长度为1的区间,将这些单独的区间进行标记,然后可解决区间长度为2,最后解决最后的大区间。例如样例
1 5
1 2
4 5
2 2
4 4
先处理4和2,然后到4-5这个区间,4肯定是最后处理的,所以4-5这个区间选择的是5,同理1-2选择的是1,那么最后的1-5区间,其他的数已经选择完,那么只能选择3。
AC code
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 5010;
struct ll
{
int l, r, len, c;
}L[N];
int n;
int sta[N];
bool cmp(ll a, ll b)
{
return a.len < b.len;
}
int main()
{
int t;
cin >> t;
while(t -- )
{
cin >> n;
memset(sta, 0, sizeof(sta));
memset(L, 0, sizeof(L));
for(int i = 1; i <= n; i ++)
{
int a, b;
cin >> a >> b;
L[i] = {a, b, b - a, 0};
}
sort(L + 1, L + 1 + n, cmp);
for(int i = 1; i <= n; i ++)
{
if(L[i].l == L[i].r)
{
sta[L[i].r] = 1;
L[i].c = L[i].l;
}
else
{
for(int j = L[i].l; j <= L[i].r; j ++)
{
if(!sta[j])
{
L[i].c = j;
sta[j] = 1;
}
}
}
}
for(int i = 1; i <= n; i ++)
{
cout << L[i].l << ' ' << L[i].r << ' ' << L[i].c << endl;
}
puts("");
}
return 0;
}
C - Balanced Stone Heaps
题意:给定一个序列,可以执行此操作,选择一个数 d ,然后将当前这个位置n的数取出 d 加到n - 1的位置,然后取出2 × d 加到n - 2的数上,0 ≤ d ≤ a[n],让坐标大于等于3的数都执行这一个操作,问最小的数最大时多少。
思路:二分,将答案进行二分,要注意的是,我们判断时候是从后往前进行此过程,但是实际上我们是从前往后进行此过程,所以一定要注意不能 d 不能大于当前数的三分之一,这个是最重要的。
AC code
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
int n;
int a[N], b[N];
bool check(int mid)
{
for(int i = 1; i <= n; i ++)
{
b[i] = a[i];
}
for(int i = n; i >= 3; i --)
{
if(b[i] < mid) return false;
int x = min((b[i] - mid) / 3, a[i] / 3);
//if(b[i] - 3 * x < mid) return true;
//b[i] -= 3 * x;
b[i - 1] += x;
b[i - 2] += 2 * x;
}
if(b[1] >= mid && b[2] >= mid)
return true;
return false;
}
int main()
{
int t;
scanf("%d", &t);
while(t -- )
{
scanf("%d", &n);
int mx = -INF, mi = INF;
for(int i = 1; i <= n; i ++)
{
scanf("%d", &a[i]);
mx = max(mx, a[i]);
mi = min(mi, a[i]);
}
int l = mi, r = mx;
//cout << l << ':' << r << endl;
while (l < r)
{
int mid = (l + r + 1) >> 1; //(l+r+1)/2
if (check(mid))
l = mid;
else
r = mid - 1;
}
printf("%d\n", l);
}
return 0;
}
感悟
前两个题还好,第三个题说实话是没有发现是二分,当发现最小值最大这个字眼二分就跑不了了,然后还有注意的是,二分的时候可以先把check函数写出,因为其中返回的时候要根据题意进行返回,暴不能根据你写的二分的分法来决定,二分的方式要根据check条件来决定。