7.24 二分搜索

二分搜索作用:降低时间复杂度到log(n);求满足条件的最大的最小值,或是最小最大值;

设计一个bool  judge 函数,判断该点是否合法(满足条件)

A题:

还记得我们新生赛上的这题Averyboy的筷子这题吗?众所周知,Averyboy是一个非常的男孩,既然是一个非常的男孩,那么他就会有许多奇葩的爱好。比如收藏筷子。现在美美旸有n双筷子,编号为1-n,同一双筷子编号相同,美美旸把这些筷子放成一排。现在美美旸对av-boy说,如果你能解决我给你出的一个问题,这些筷子都归你。美美旸的问题是:把这些筷子通过一些操作,使得最后这些筷子是同一双的一定相连。每次的操作是,你可以从这2n支筷子中任意取出一支,剩下的筷子自动合并在一起,然后把这支筷子插入任意一个位置,包括两端。(操作次数无限制。)为了刁难av-boy,美美旸故意定了一个条件,每次只能取出编号大于等于x的筷子。现在你的问题是找出最大的x(1 <= x <= n),使得av-boy一定能顺利拿到筷子。

 这道题的意思就是说选择一个编号为x的筷子,编号大于等于x的筷子都可以随意移动,那就相当于把编号大于等于x的筷子都删掉,看剩下的筷子编号相同的是不是都连在一起就行,因为剩下的筷子是移动不了的,只能自动合并。由此我们设计出bool judge函数
接下来二分搜索最大的x即可,注意筷子是2*n个
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=1e5+10;
 4 int a[maxn];
 5 int b[maxn];
 6 int k,n;
 7 bool judge(int k)
 8 {
 9     int i;
10     int cnt=1;
11     for(i=1;i<=2*n;i++)      
12     {
13         if(a[i]<k)
14         {
15             b[cnt++]=a[i];
16         }
17     }
18     cnt--;
19     for(i=1;i<=cnt-1;i++)
20     {
21         if(i&1)
22         {
23             if(b[i+1]!=b[i])return false;
24         }
25     }
26     return true;
27 }
28 int bisearch()
29 {
30     int l=1,r=n;
31     int ans=0;
32     while(l<=r)
33     {
34         int mid=(l+r)>>1;
35         if(judge(mid))
36         {
37             ans=mid;
38             l=mid+1;
39         }
40         else r=mid-1;
41     }
42     return ans;
43 }
44 int main()
45 {
46    int t;
47    cin>>t;
48    while(t--)
49    {
50        scanf("%d",&n);
51        for(int i=1;i<=2*n;i++)scanf("%d",&a[i]);
52        int ans=bisearch();
53        printf("%d\n",ans);
54    }
55     return 0;
56 }
View Code

B题:

现在有N种物品,每一种物品有一个基础价值a[i],当买k件物品时,第i件物品的最终价值为a[i] + k * i,现在给你S元,你最多能买多少件物品.

 最原始的问题,确定一个k,则每件物品的最终价值都被确定;
设计bool  judge 函数,对物品的最终价值进行排序,选择最小的k件求和,若和>s,则不合法;
二分查找最大的k;注意如果i*j的乘积很大,则i,j都要开long long ,不然会爆
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
long long a[maxn];
long long b[maxn];
long long n;
long long s;
bool judge(long long k)
{
    int i;
    for(i=1;i<=n;i++)
    {
        b[i]=a[i]+i*k;
    }
    sort(b+1,b+n+1);
    long long sum=0;
    for(i=1;i<=k;i++)
    {
        sum+=b[i];
    }
    if(sum<=s)return true;
    else return false;
}
long long bisearch()
{
    int l=1,r=n;
    long long ans=0;
    while(l<=r)
    {
        long long mid=(l+r)>>1;
        if(judge(mid))
        {
            ans=mid;
            l=mid+1;
        }
        else r=mid-1;
    }
    return ans;
}
int main()
{

    int t;
    cin>>t;
    while(t--)
    {
        scanf("%d%lld",&n,&s);
        int i;
        for(i=1;i<=n;i++)scanf("%d",&a[i]);
        long long ans=bisearch();
        printf("%d\n",ans);
    }
    return 0;
}
View Code

C题:

众所周知,averyboy是一个非常男孩。天外天给你他一个问题。问题如下:给你一个长度为N的序列a[1]~a[N]和一个整数sum,我们称一个区间为averyboynb区间,当且仅当这个区间的所有数的和不超过sum。现在你需要找出一个区间和最大的averyboynb区间。

枚举左端点,二分查找右端点;

对于每一个左端点,二分求解满足条件的最大的右端点

猜你喜欢

转载自www.cnblogs.com/raincle/p/9367921.html
今日推荐