这两天的训练赛都有一道二分的题,但是都没往二分上面想,同样不知道怎么二分。
D. Fast and Fat
思路
二分的关键也就是check函数怎么写了,求队伍最大速度,可以分为速度>=mid和<mid两部分,再判断,能不能实现速度大的背小的,并且速度>=mid.
代码
#include<bits/stdc++.h>
using namespace std;
# define int long long
int n;
struct pi{
int v,w;
}a[100005];
bool cmp1(pi a,pi b)
{
return a.v+a.w>b.v+b.w;
}
bool cmp2(pi a,pi b)
{
return a.w>b.w;
}
int check(int x)
{
vector<pi> s;//存放速度小的,需要被背着
vector<pi> q;//存速度大的,
for(int i=1;i<=n;i++)
{
if(a[i].v>=x)
q.push_back(a[i]);
else s.push_back(a[i]);
}
if(q.size()<s.size())
return 0;
sort(q.begin(),q.end(),cmp1);//速度可能会变为vi+wi-wj,所以按vi+wi的大小顺序排
sort(s.begin(),s.end(),cmp2);//w从大到小排。
//无需考虑太多,如果最大的vi+wi去背wj,速度达不到,那也不用考虑其他的了,必须要保证每个小的都被背
for(int i=0;i<s.size();i++)
{
if(q[i].v+q[i].w-s[i].w<x)
return 0;
}
return 1;
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i].v>>a[i].w;
int l=-1,r=1e9+10;
while(l<r)//这是小于等于最大值的二分
{
int mid=(l+r+1)>>1;
if(check(mid))
l=mid;
else r=mid-1;
}
cout<<l<<'\n';
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie();
int t;
cin>>t;
while(t--)
{
solve();
}
}
I. Path Planning
思路
用一个map,键存位置,值存数字,关于check函数,我一直想的都是i,j,i+j…但这些其实可以不考虑,要满足向右下走,用两重循环,i的值在不断增大,此时已经是向下,这时只需要,设个变量判断j,就可以了
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
map<pair<int,int>,int> ma;
int n,m;
int check(int x)//这样判断很巧妙,而且首尾数字是什么,都无关紧要
{
int k=0;
for(int i=1;i<= n;i++)
for(int j=1;j<= m;j++)//如果是一行或一列,不需要特殊考虑,因为j逐步增大
{
if(ma[{i,j}]<x)
{
if(j<k) return 0;
k=j;
}
}
return 1;
}
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>ma[{i,j}];//这里将map和pair结合,赛时也没想到
int l=0,r=n*m;
while(l<r)
{
int mid=l+r+1>>1;
if(check(mid))
l=mid;
else r=mid-1;
}
cout<<l<<'\n';
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while(t--)
{
solve();
}
}