2018-07-24 二分三分练习题

  • A  -- Can you find it?

  • Description

Give you three sequences of numbers A, B, C, then we give you a number X. Now you need to calculate if you can find the three numbers Ai, Bj, Ck, which satisfy the formula Ai+Bj+Ck = X.

  • Input

There are many cases. Every data case is described as followed: In the first line there are three integers L, N, M, in the second line there are L integers represent the sequence A, in the third line there are N integers represent the sequences B, in the forth line there are M integers represent the sequence C. In the fifth line there is an integer S represents there are S integers X to be calculated. 1<=L, N, M<=500, 1<=S<=1000. all the integers are 32-integers.

  • Output

For each case, firstly you have to print the case number as the form "Case d:", then for the S queries, you calculate if the formula can be satisfied or not. If satisfied, you print "YES", otherwise print "NO".

  • Sample Input

3 3 3

1 2 3

1 2 3

1 2 3

3

1

4

10

  • Sample Output

Case 1:

NO

YES

NO

  • 题目理解

这道题去年也做过但是没有理解。拿到题目知道要用二分但是由于对时间复杂度的理解不深导致去年一直对c数组二分而不是对求和数组二分,直接超时。对sum求和数组排序去重;遍历c数组然后X减去每个数得到的每个解,对sum数组二分查找

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=505;
int a[maxn],b[maxn],c[maxn];
int sum[maxn*maxn];
bool find_sum(int x,int h){
     int l=0,mid=0;
     while(l<=h){
        mid=(l+h)/2;
        if(x==sum[mid])
            return true;
        else if(x<sum[mid])
            h=mid-1;
        else
            l=mid+1;
     }
     return false;
}
int main()
{
    int l,n,m,s,x;
    int Case=0;
    while(scanf("%d%d%d",&l,&m,&n)!=EOF){
        for(int i=0;i<l;++i) scanf("%d",&a[i]);
        int len=0;
        for(int i=0;i<n;++i){
            scanf("%d",&b[i]);
            for(int k=0;k<l;++k){
                sum[len++]=b[i]+a[k];
            }
        }
        for(int i=0;i<m;++i) scanf("%d",&c[i]);
        sort(sum,sum+len);
        len=unique(sum,sum+len)-sum;//排序后相邻的才能后移
        //for(int i=0;i<len;++i) printf("%d\n",sum[i]);
        scanf("%d",&s);
        printf("Case %d:\n",++Case);
        while(s--){
            scanf("%d",&x);
            int i=0;
            while(i!=m){
                int tmp=x-c[i];
                if(find_sum(tmp,len))
                    break;
                i++;
            }
            if(i<m)printf("YES\n");
            else printf("NO\n");
        }
    }
    return 0;
}

 

  • B  -- 修路

  • Description

前段时间,某省发生干旱,B山区的居民缺乏生活用水,现在需要从A城市修一条通往B山区的路。假设有A城市通往B山区的路由m条连续的路段组成,现在将这m条路段承包给n个工程队(n m ≤ 300)。为了修路的便利,每个工程队只能分配到连续的若干条路段(当然也可能只分配到一条路段或未分配到路段)。假设每个工程队修路的效率一样,即每修长度为1的路段所需的时间为1。现在给出路段的数量m,工程队的数量n,以及m条路段的长度(这m条路段的长度是按照从A城市往B山区的方向依次给出,每条路段的长度均小于1000),需要你计算出修完整条路所需的最短的时间(即耗时最长的工程队所用的时间)

  • Input

第一行是测试样例的个数T ,接下来是T个测试样例,每个测试样例占2行,第一行是路段的数量m和工程队的数量n,第二行是m条路段的长度

  • Output

对于每个测试样例,输出修完整条路所需的最短的时间

  • Sample Input

2

4 3

100 200 300 400

9 4

250 100 150 400 550 200 50 700 300

  • Sample Output

400

900

  • 题目理解

求最小的最大,二分答案然后更加答案情况在判断区间状况最后得到符合题目的答案;0-1问题可以用dp但是逻辑转移容易出错。刚开始的最大值是一定满足的所以将ans赋为该值,根据mid是否成立:成立ans=mid,接着缩小区间;不成立直接缩小区间l=mid+1

#include<cstdio>
const int maxn=3005;
int load[maxn];
bool check_right(int ans,int m,int n){
    int sum=0;
    for(int i=0;i<m;++i){
        if(ans<load[i]) return false;
        if(ans-sum>=load[i])
            sum+=load[i];
        else{
            n--;
            sum=load[i];
        }
    }
    if(sum) n--;
    if(n<0) return false;
    else return true;
}
int main()
{
    int ans,t,m,n;
    while(scanf("%d",&t)!=EOF){
        while(t--){
            scanf("%d%d",&m,&n);
            ans=0;
            for(int i=0;i<m;++i){
                scanf("%d",&load[i]);
                ans+=load[i];
            }
            int l=0,mid=0;
            while(l<ans){
                mid=(l+ans)/2;//printf("%d  %d  %d\n",l,ans,mid);
                if(check_right(mid,m,n))
                    ans=mid;
                else
                    l=mid+1;
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

 

  • C  -- Can you solve this equation?

  • Description

Now,given the equation 8*x^4 + 7*x^3 + 2*x^2 + 3*x + 6 == Y,can you find its solution between 0 and 100;
Now please try your lucky.

  • Input

The first line of the input contains an integer T(1<=T<=100) which means the number of test cases. Then T lines follow, each line has a real number Y (fabs(Y) <= 1e10);

  • Output

For each test case, you should just output one real number(accurate up to 4 decimal places),which is the solution of the equation,or “No solution!”,if there is no solution for the equation between 0 and 100.

  • Sample Input

2

100

-4

  • Sample Output

1.6152

No solution!

  • 题目理解

在区间 [ 0,100 ] 这是一个明显的增函数;首先通过两个端点判断是否有解,否则No solution!;接着二分计算缩小区间,当区间缩小到精度范围内可以输出结果。可以通过循环次数控制结束也可以h-l<eps结束循环。

#include<cstdio>
int cal(double x,double y){
    double sum=8*x*x*x*x+7*x*x*x+2*x*x+3*x+6;
    if(sum==y) return 0;
    else if(sum<y) return -1;
    else return 1;
}
int main()
{
    int t;
    while(scanf("%d",&t)!=EOF){
        while(t--){
            double x,y,l=0,h=100;
            scanf("%lf",&y);
            int resl=cal(0,y);
            int resh=cal(100,y);
            int res=resl*resh;
            if(res==1){
                printf("No solution!\n");
            }
            else{
               for(int i=0;i<100;++i){
                  x=(l+h)/2;
                  //printf("%lf %lf %lf\n",l,h,x);
                  res=cal(x,y);
                  if(!res)
                    break;
                  else if(res==-1)
                    l=x;
                  else
                    h=x;
               }
               printf("%.4lf\n",x);
            }
        }
    }
    return 0;
}

 

  • G -- 搬运工小明

  • Description

作为老人的小明非常忧伤,因为他马上要被流放到本部去了,住进全左家垅最有历史感的11舍真是一件非常荣幸的事情。
搬行李是个体力活,小明发现自己的行李太多啦,所以他决定去买很多个袋子来装走。到了超市的小明发现,不同大小的袋子居然价格一样???虽然买最大的自然最赚,但是小明是名远近闻名的环保人士,他觉得袋子只要能装下他的行李就够了,并且为了不麻烦收银的小姐姐(⊙o⊙)…,他也只会购买同一种大小的袋子。因此他希望在能装下所有行李的前提下,袋子越小越好。同时为了避免弄乱行李,小明希望同一个袋子装的是位置连续相邻的行李。小明摸了摸口袋发现自己带的钱最多能买N个袋子,数学特别差的他不知道到底该买多大的才合适,所以想靠你来解决这个问题了

  • Input

第一行为一个数字T(T<=10)表示数据组数
第二行为两个数字N(N <= 10^5)和 M(M <= 10^5)表示袋子个数和小明的行李个数
第三行为M个数字,第i个数字a[i]表示小明的第i个行李体积为a[i](0<a[i] <= 10^9)

  • Output

输出一行表示袋子的最小体积(整数)

  • Sample Input

1

3 3

1 1 1

  • Sample Output

1

  • 题目理解

思路和B题一模一样,简直就是把连续的路换成了连续的袋子。但是需要注意的是这里极限解int已经溢出需要使用long long

#include<cstdio>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn=100005;
ll w[maxn];
bool check_right(ll ans,int m,int n){
    ll sum=0;
    for(int i=0;i<m;++i){
        if(ans<w[i]) return false;
        if(ans-sum>=w[i])
            sum+=w[i];
        else{
            n--;
            sum=w[i];
        }
    }
    if(sum) n--;
    if(n<0) return false;
    else return true;
}
int main()
{
    int t,m,n;
    ll ans;
    while(scanf("%d",&t)!=EOF){
        while(t--){
            scanf("%d%d",&n,&m);
            ans=0;
            for(int i=0;i<m;++i){
                scanf("%lld",&w[i]);
                ans+=w[i];
            }
            ll l=0,mid=0;
            while(l<ans){
                mid=(l+ans)/2;//printf("%lld  %lld  %lld\n",l,ans,mid);
                if(check_right(mid,m,n))
                    ans=mid;
                else
                    l=mid+1;
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}

 

  • J  -- Strange fuction

  • Description

Now, here is a fuction:
F(x) = 6 * x^7+8*x^6+7*x^3+5*x^2-y*x (0 <= x <=100)
Can you find the minimum value when x is between 0 and 100.

  • Input

The first line of the input contains an integer T(1<=T<=100) which means the number of test cases. Then T lines follow, each line has only one real numbers Y.(0 < Y <1e10)

  • Output

Just the minimum value (accurate up to 4 decimal places),when x is between 0 and 100.

  • Sample Input

2

100

200

  • Sample Output

-74.4291

-178.8534

  • 题目理解

对函数进行求导得到G(x)=42x^{6}+48x^{5}+21x^{3}+10x-y当y != 0的时候函数具有先减后增则当G(x)等于0 的时候就是极大/极小值也是最大/最小值。这时候转变为y=42x^{6}+48x^{5}+21x^{3}+10x看做x轴平移,函数为增函数二分即可,就是将y(x)与Y比较缩小区间

#include<cmath>
#include<cstdio>
double F(double x,double y)
{
	return 6*pow(x,7)+8*pow(x,6)+7*pow(x,3)+5*pow(x,2)-y*x;
}
double f(double x)
{
	return 42*pow(x,6)+48*pow(x,5)+21*pow(x,2)+10*x;
}
int main()
{
	int t;
	double y;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%lf",&y);
		double l=0,r=100,mid=0;
		while(r-l>1e-7)
		{
			mid=(l+r)/2;
			if(f(mid)<y) l=mid;
			else r=mid;
		}
		printf("%.4lf\n",F(mid,y));
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值