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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章