Acwing2024蓝桥杯二分

洛谷暂时暂停,还有一个月,准备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;
}
  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值