有关二分答案的习题

木棍

有N(1≤N≤100)根木棍(用途不详),它们的长度都为正整数。这些棍子中有一些太长了,于是,Fatwen现在想将一些棍子(可以任选)砍成多段(每段的长度任意,不需要相等),以使这些棍子(包括砍出来每一段的和没有砍的那些棍子)中最长的那根的长度最短。Fatwen是个喜欢整数的人(因为他只学过整数运算...),所以他还要求砍完后的每根棍子的长度仍为正整数。

显然,将一根棍子砍成K段须要砍K-1下。

众所周知Fatwen是个很懒的人,所以他希望对所有棍子总共只用砍不超过M下就能达到目的。现在,给出N,M和每根棍子的长度,Fatwen问你在总共最多只砍不超过M下的大前提下,他所得到的棍子中最长的那根可以有多短。

输入格式

第一行,两个正整数N和M,1≤N≤100,0≤M≤1000000;

以下N行,每行一个小于10000的正整数,表示某根棍子的长度。

输出格式

一行,一个正整数,表示在所的符合题意的砍法中,得到的木棍中的最长的那根的最小值。

输入/输出例子1

输入:

2 3
7
10

输出:

4
代码:
#include<bits/stdc++.h>
using namespace std;
long long n,k,a[200005],mid,maxx;
long long check(long long x){
    int s=0;
    for(int i=1;i<=n;i++)
    {
        s+=(a[i]/x-1);
        if(a[i]%x>0)s++;
    }
    if(s>k)return 1;
    return 0;
}
int main(){
    scanf("%lld%lld",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        maxx=max(maxx,a[i]);
    }
    long long l=0,r=maxx;
    while(l+1<r)
    {
        mid=(l+r)/2;
        if(check(mid))l=mid;
        else r=mid;
    }
    printf("%lld",r);
    return 0;
}

找数字

给出一个整数n, 小明想找到一个最小的整数x, 使得x同时满足如下条件:

1. x >=n。

2. 存在两个非负整数a和b,使得满足x = a*a*a + a*a*b + a*b*b + b* b*b。

请你帮帮忙。

输入格式

一行,一个整数n,0<=n<=10^18。

输出格式

一个整数,表示最小满足条件的x。

输入/输出例子1

输入:

9

输出:

15
样例解释

当a=2, b=1时,x=15, 满足x>=9, 且x=15已经是最小的满足条件的了。

代码:
#include<bits/stdc++.h>
using namespace std;
long long x,minn=LONG_MAX;
int main(){
    cin>>x;
    for(long long i=1;i<=1e+6;i++)
    {
    	long long l=1,r=1000005,m=0;
    	while(l<r)
        {
            m=(l+r)/2;
            if(i*i*i+i*i*m+i*m*m+m*m*m<x)l=m+1;
            else r=m;
        }
        if((i*i*i+i*i*r+i*r*r+r*r*r)>=x)minn=min(minn,i*i*i+i*i*r+i*r*r+r*r*r);
    }
    cout<<minn;
    return 0;
}

202312NHOI 第五题 文本框

小慧把她学会的英文单词记录了下来,现在她希望在一个文本框里完全显示出她记录的单词库。已知这个文本框最多只能显示M行,小慧的单词库有N个单词,要求按原次序显示所有单词,每个单词至少要用一个空格分开,而且一个单词的所有字母必须放在同一行。问这个文本框至少需要多宽才能满足小慧的需求。

输入格式

第一行,两个正整数N,M。

第二行,N个正整数,表示每个单词的长度。

【数据范围】

对于40%的数据,1<=N,M<=10^3,每个单词的长度<=10^2。

对于100%的数据,1<=N,M<=2*10^5,每个单词的长度<=10^9。

输出格式

能把所有单词显示出来的文本框的最少宽度。

输入/输出例子1

输入:

13 3

9 5 2 7 1 8 8 2 1 5 2 3 6

输出:

26

输入/输出例子2

输入:

30 8
8 55 26 97 48 37 47 35 55 5 17 62 2 60 23 99 73 34 75 7 46 82 84 29 41 32 31 52 32 60

输出:

189
代码:
#include<bits/stdc++.h>
using namespace std;
long long n,x,a[1000005],sum;
int main(){
    cin>>n>>x;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        sum=sum+a[i];
    }
    long long l=1,r=sum,m=0;
    while(l<r)
    {
        m=(l+r)/2;
        long long sum=1,ans=-1;
        for(int i=1;i<=n;i++)
        {
            if(a[i]+ans+1<=m)ans=ans+a[i]+1;
            else sum++,ans=a[i];
        }
        if(sum>x)l=m+1;
        else r=m;
    }
    cout<<r;
    return 0;
}

牛栏

FJ新建了一个有N(2≤N≤100000)个畜栏的畜棚。畜栏的位置分布在直线的点x_1, ..., x_N(0≤x_i≤1000000000)上。

他的C(2≤C≤N)只牛不喜欢这个畜棚的设计并且对在同一个畜栏里的其他牛进行攻击。为了防止牛受到伤害,FJ想把这些牛分配到某些畜栏中,使得这些牛所在的任意两个畜栏之间的最短距离尽可能长。求最长的最短距离是多少?

输入格式

第一行,两个用空格隔开的整数,N和C;

第二至第N+1行,每行包括一个整数,畜栏的位置:X_i。

输出格式

一行,一个整数,表示最长的最短距离。

输入/输出例子1

输入:

5 3

1

2

8

4

9

输出:

3

样例解释

FJ把3只牛放到位置是1、4和8的畜栏里,最短距离是3。

代码:
#include<bits/stdc++.h>
using namespace std;
long long n,c,q[100005],maxx=-1,minn=1000000001;
int main(){
    cin>>n>>c;
    for(int i=1;i<=n;i++){
        cin>>q[i];
        maxx=max(q[i],maxx);
        minn=min(q[i],minn);
    }
    sort(q+1,q+1+n);
    if(c==2){
        cout<<q[n]-q[1];
        return 0;
    }
    long long l=minn,r=maxx,m=0,t=0,ans=0,k=1;
    while(l<=r){
        m=(l+r)/2,t=c,k=1;
        for(int i=2;i<=n&&t!=0;i++)
            if(q[i]-q[k]>=m)k=i,t--;
        t--;
        if(t>0)r=m-1;
        else ans=max(ans,m),l=m+1;
    }
    cout<<ans;
    return 0;
}

 【基础】伐木工

伐木工人米尔科需要砍够M米长的木材。这是一个对米尔科来说很容易的工作,因为他有一个漂亮的新伐木机,可以像野火一样砍倒森林。不过,米尔科只被允许砍倒单行树木。
米尔科的伐木机工作过程如下:米尔科设置一个高度参数H(米),伐木机升起一个巨大的锯片到高度H,并锯掉所有的树比H高的部分(当然,树木不高于H米的部分保持不变)。米尔科就行到树木被锯下的部分。
例如,如果一行树的高度分别为20,15,10和17,米尔科把锯片升到15米的高度,切割后树木剩下的高度将是15,15,10和15,而米尔科将从第1棵树得到5米,从第4棵树得到2米,共得到7米木材。
米尔科非常关注生态保护,所以他不会砍掉过多的木材。这正是他为什么尽可能高地设定伐木机锯片的原因。帮助米尔科找到伐木机锯片的最大的整数高度H,使得他能得到木材至少为M米。换句话说,如果再升高1米,则他将得不到M米木材。

输入

第1行:2个整数N和M,N表示树木的数量(1<=N<=106),M表示需要的木材总长度(1<=M<=2 * 109)
第2行:N个整数表示每棵树的高度,值均不超过109。所有木材长度之和大于M,因此必有解。

输出

1个整数,表示砍树的最高高度。

样例输入
5 20
4 42 40 26 46
样例输出
36
代码:
#include<bits/stdc++.h>
using namespace std;
int a[1000005];
long long n,m,l=0,mid,r,t=0;
int ef(int x){
    long long sum=0;
    for(int i=1;i<=n;i++){
        if(a[i]>x)sum=sum+a[i]-x;
    }
    if(sum>=m)return 1;
    return 0;
}
int main(){
    scanf("%lld %lld",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        if(t<a[i])t=a[i];
    }
    r=t;
    while(l<r){	  
        mid=(l+r+1)/2;
        if(ef(mid))l=mid;
        else r=mid-1;
    }
    printf("%lld\n",l);
    return 0;
}

 【提高】买木头

有n个木材供应商(1≤n≤10000),每个供货商有长度相同一定数量的木头。长木头可以锯短,但短木头不能接长。有一个客人要求m根长度相同的木头。要求计算出,此时供货商提供的木头满足客人要求的最长的长度是多少。
例如n=2,m=30,两个供货商的木头为
12,10     第1个供货商的木头长度为12,共有10根;
5,10      第2个供货商的木头长度为5,共有10根。
计算的结果为5,即长度为12的木头一根可锯出两根长度为5的木头,多余的无用,长度为5的木头不动,此时可得到30根长度为5的木头。

输入

整数n,m,l_1,s_1(1≤m≤1000000,1≤l_1≤10000,1≤s_1≤100)
其中l_1是第一个供货商木头的长,s_1是第一个供货商木头数量。其他供货商木头的长度和数量l_i和s_i(i≥2),由下面的公式给出:
l_i=((l_(i-1)×37011+10193)  mod 10000)+1
s_i=((s_(i-1)×73011+24793)  mod 100)+1

输出

一个整数,即满足要求的m根长度相同的木头的最大长度。

样例输入
10 10000 8 20
样例输出
201
代码:
#include<bits/stdc++.h>
using namespace std;
long long n,m,l[100005],s[100005];
bool ef(long long x){
	long long cnt=0;
	for(int i=0;i<n;i++)
		cnt+=(l[i]/x)*s[i];
	return cnt>=m;
}
int main(){
	cin>>n>>m>>l[0]>>s[0];
	for(int i=1;i<n;i++){
		l[i]=((l[i-1]*37011+10193)%10000)+1;
		s[i]=((s[i-1]*73011+24793)%100)+1;
	}
	long long l=1,r=1e18,ans=0;
	while(l<=r){
		long long mid=(l+r)>>1;
		if(ef(mid)){
			ans=mid;
			l=mid+1;
		}
		else r=mid-1;
	}
	cout<<ans;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值