洛谷暂时暂停,还有一个月,准备4月13号蓝桥杯,内容仅供参考,不足之处望理解
两种基础二分模板:
int check(int ans) { ... ;}
//右边界确定
int left = 1, right = n;
while (left < right) {
int mid = (left + right) / 2;
if (check(mid) == num)
right = mid;
else
left = mid + 1;
}
int check(int ans) { ... ;}
//右边界不确定,定义为较大值
int left=1,right=1e9;
while(left<right){
int mid=(left+right+1)/2;
if(check(mid)==num)
right=mid-1;
else
left=mid;
}
AcWing 503. 借教室
//头文件
#include<iostream>
#include<cstring> //使用memset函数
using namespace std;
//定义各变量
const int N = 1e6 + 5;
int n, m, startx[N], endx[N];
long long have[N], need[N], ans[N], diff[N];
//check(x)代表的是检查到1到x的订单是否可以被完成
int check(int x) {
//每次检查要更新diff数组
memset(diff, 0, sizeof(diff));
//差分(1到x)
for (int i = 1; i <= x; i++) {
diff[startx[i]] += need[i]; //开始
diff[endx[i] + 1] -= need[i]; //结束
}
//求每天(1到n天)的订单之和ans[i]
for (int i = 1; i <= n; i++) {
//一维前缀和
ans[i] = ans[i - 1] + diff[i];
//如果订单>现有的数量时,1到x订单无法完成,返回0
if (ans[i] > have[i]){
return 0;
}
}
//1到x所有订单都可以完成,返回1
return 1;
}
int main() {
//输入
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> have[i];
for (int i = 1; i <= m; i++) { cin >> need[i] >> startx[i] >> endx[i]; }
//如果m个订单都可以完成时,输出并且返回
if (check(m) == 1) { cout << "0" << endl; return 0; }
//二分答案
int left = 1, right = m;
while (left < right) {
int mid = (left + right) / 2;
if (check(mid) == 0)
right = mid;
else
left = mid + 1;
}
//输出
cout << "-1" << endl << left << endl;
return 0;
}
AcWing 1227. 分巧克力(第八届省赛)
#include<iostream>
using namespace std;
const int n=1e5+5;
int cho,peo,len[n],wid[n];
//check(x)函数为判断把巧克力分成 x*x 大小时,是否够分
int check(int x){
//ans可以分的巧克力的数目
long long ans=0;
//遍历每一块巧克力求和
for(int i=1;i<=cho;i++) ans+=(len[i]/x)*(wid[i]/x);
if(ans<peo) return 0; //巧克力数<人数,x大了
else return 1; //巧克力数>=人数,x小了
}
int main(){
//输入
cin>>cho>>peo;
for(int i=1;i<=cho;i++) cin>>len[i]>>wid[i];
//二分答案
int left=1,right=1e5; //右边界为较大值
while(left<right){
int mid=(left+right+1)/2;
if(check(mid)==0) right=mid-1;
else left=mid;
}
//输出
cout<<left<<endl;
return 0;
}
AcWing 5407. 管道(第十四届省赛)
未AC (73points):
#include<iostream>
#include<cstring> //memset函数
using namespace std;
const int N=1e5+5;
int n,len,l[N],t[N],flag[N];
//check(x)函数判断第x个时间单位后,管道是否有水流
int check(int x){
//每次检查初始化flag数组
memset(flag,0,sizeof(flag));
//遍历 n 组数据
for(int i=1;i<=n;i++){
if(t[i]<=x){ //在x时间以内阀门才可以开
//x时间后,找水流的左右边界
int temp=x-t[i];
int maxx=l[i]+temp;
int minn=l[i]-temp;
//注意边界在 1 到 len 内
if(maxx>len) maxx=len;
if(minn<1) minn=1;
//标记有水流的flag数组
for(int i=minn;i<=maxx;i++) flag[i]=1;
}
else{ //否则继续遍历
continue;
}
}
//遍历flag数组进行判断
for(int i=1;i<=len;i++){
if(flag[i]==0){
return 0;
}
}
return 1;
}
int main(){
//输入
cin>>n>>len;
for(int i=1;i<=n;i++) cin>>l[i]>>t[i];
//二分答案
int left=1,right=len; //右边界最大是len
while(left<right){
int mid=(left+right)/2;
if(check(mid)==1) right=mid;
else left=mid+1;
}
//输出
cout<<left<<endl;
return 0;
}
AcWing 4656. 技能升级(第十三届省赛)
未AC (39points):
#include<iostream>
#include<algorithm> //sort(数组+开始位置,数组+结束位置的下一个位置,cmp)
using namespace std;
const int N=1e6+5;
int n,m,a[N],b[N],num[N];
int main(){
ios::sync_with_stdio(false);
cin>>n>>m;
int j=0;
//暴力法
for(int i=1;i<=n;i++) {
cin>>a[i]>>b[i];
//每输入一组数据,就把该数据所有可加技能点存进num数组
num[j++]=a[i];
int temp=a[i]-b[i];
while(temp>0){
num[j++]=temp;
temp-=b[i];
}
}
//sort排序
sort(num,num+j+1);
long long ans=0;
//从大到小依次求和
for(int i=j;i>j-m;i--) {ans+=num[i];}
cout<<ans<<endl;
return 0;
}
AcWing 4956. 冶炼金属(第十四届省赛)
未AC(60points):
#include<iostream>
using namespace std;
const int N=1e4+5;
int n,a[N],b[N];
int main(){
cin>>n;
//先找最大值
int maxx=1e9;
for(int i=1;i<=n;i++){
cin>>a[i]>>b[i];
int temp=a[i]/b[i];
maxx=min(temp,maxx);
}
// maxx==1 时的特殊情况,输出返回
if(maxx==1) { cout<<"1 1"<<endl; return 0; }
//通过最大值往后遍历
for(int i=maxx-1;i>=1;i--){
for(int j=1;j<=n;j++){
//找到最小值,输出返回
if(a[j]/i==b[j]+1){
cout<<i+1<<" "<<maxx<<endl;
return 0;
}
}
}
return 0;
}