因为马上要比赛了,但是自己的二分有时候还是会出问题,所以打算整理一个二分专题
先罗列一些题目和code,题解晚点发
洛谷P1824 进击的奶牛
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int dx[8]={-1, 0, 1, 0, 1, -1, 1, -1};
const int dy[8]={0, 1, 0, -1, -1, 1, 1, -1};
const int N=1e5+10;
int a[N];
int INF=1e9;
int n,c,ans;
int l,r;
bool judge(int d)
{
int k=0,last=-INF;
for(int i=1;i<=n;i++)
{
if(a[i]-last>=d)
{
last=a[i];
k++;
}
}
return k>=c;
}
void solve()
{
cin>>n>>c;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
int l=0,r=INF;
while(l<=r)
{
int mid=l+r>>1;
if(judge(mid))
{
ans=mid;
l=mid+1;
}else{
r=mid-1;
}
}
cout<<ans<<endl;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int T = 1;
//cin >> T;
while(T--) solve();
}
洛谷 P1873[COCI 2011/2012 #5] EKO / 砍树
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
#define int ll
const int dx[8]={-1, 0, 1, 0, 1, -1, 1, -1};
const int dy[8]={0, 1, 0, -1, -1, 1, 1, -1};
const int N=1e6+10;
int a[N];
int INF=4e5+10;
int n,m;
int l,r,ans;
bool judge(int d)
{
int sum=0;
for(int i=1;i<=n;i++)
{
sum+=max((ll)0,a[i]-d);
}
if(sum>=m) return true;
else return false;
}
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
int l=0,r=INF;
while(l<=r)
{
int mid=l+r>>1;
if(judge(mid))
{
ans=mid;
l=mid+1;
}else{
r=mid-1;
}
}
cout<<ans<<endl;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int T = 1;
//cin >> T;
while(T--) solve();
}
Codeforces Round 936 C. Tree Cutting
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e6 + 10;
ll n, m;
vector<ll>a[N];
ll cnt;
ll k;
ll dfs(ll son,ll fa,ll x)
{
ll sum=1;
for(auto b:a[son])
{
if(b==fa) continue;
sum+=dfs(b,son,x);
}
if(sum>=x)
{
cnt++;
return 0;
}
else return sum;
}
bool check(int x)
{
cnt=0;
dfs(1,-1,x);
return cnt>k;
}
void solve() {
cin>>n>>k;
for(int i=1;i<=n;i++)
{
a[i].clear();
}
ll t=n-1;
while(t--)
{
ll u,v;
cin>>u>>v;
a[u].push_back(v);
a[v].push_back(u);
}
int left=1,right=n;
while(left+1<right)
{
int mid=(left+right)>>1;
if(check(mid)) left =mid;
else right=mid;
}
if(check(right)) cout<<right<<endl;
else cout<<left<<endl;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int T;
cin >> T;
while(T--) solve();
return 0;
}
P1182 数列分段 Section II
思路是二分答案,刚开始做这题的时候犯了两个错误。一个是边界问题,check函数中如果最后sum还含有元素,还要计数。另一个是L和R范围问题,这里的L要设置为数组中最大的数,R要设置为数组的总和,为什么呢,因为有种数据是:
输入
3 3
3 4 5
输出
5
如果L初始设置为0,那输出就是3,因为虽然数组中的4和5大于3,但是每个元素计一次数刚好3次符合条件。
AC code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
#define int ll
const int dx[8]={-1, 0, 1, 0, 1, -1, 1, -1};
const int dy[8]={0, 1, 0, -1, -1, 1, 1, -1};
const int N=1e6+10;
const double INF=1e9+10;
int a[N];
int n,m,ans,res=0,k=0;
bool check(int d){
int cnt=0;
int sum=0;
for(int i=1;i<=n;i++)
{
if(sum+a[i]>d)
{
sum=0;
cnt++;
}
sum+=a[i];
}
if(sum) cnt++;
if(cnt<=m) return true;
else return false;
}
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
res+=a[i];
k=max(k,a[i]);
}
int l=k,r=res;
while(l<=r)
{
int mid=l+r>>1;
if(check(mid))
{
ans=mid;
r=mid-1;
}else{
l=mid+1;
}
}
cout<<ans<<endl;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int T = 1;
//cin >> T;
while(T--) solve();
return 0;
}