结构体排序,二分

今年暑假不AC

 HDU - 2037 

 思路:

贪心,结构体排序

按照每个节目的结束时间先后排序,之后在遍历时,我们从头开始看,在看完第一个节目后,我们紧跟着看最先开始的第二个节目,怎么看谁先开始呢,由于已经按照结束时间排好了,所以我们选紧跟着他最先开始的那个节目作为第二个节目。

画个图自己感受一下哈:(高能预警)

 

可以看出,虽然第四条线开始的晚,但是由于是按结束时间排好的,而排完后第二三条线开始时间虽然早但是那时候第一个节目还没有结束,所以不能选,之后的依然如此

 

#include <iostream>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>

using namespace std;

struct node
{
    int start;
    int end;

}time[110];

bool cmp(node x, node y)
{
    return x.end < y.end;
}

int main()
{
    int n;
    while(cin >> n , n)
    {
        for (int i = 0; i < n; i++) cin >> time[i].start >> time[i].end;

        sort(time, time + n, cmp);
        int cnt = 1;//因为最少也能看一个节目,所以cnt初值为1
        int end = time[0].end;
        for (int i = 0; i < n; i++)
        {
            if (time[i].start >= end)
            {
                cnt++;
                end = time[i].end;
            }
        }
        cout << cnt << endl;
    }
    return 0;
}

 

然后这里说一下当有多个排序条件时应该怎样排序,比如一群人有身高,体重,年龄,智商,情商,颜值等信息,你需要这么排:先按颜值排序,长得好看的排前面,如果长得一样好看,再按身高排序,高的排前面,如果升高也相同,就按体重排序,轻的排前面,体重相同就按智商,智商相同按情商,情商相同就按年龄,年龄小的排前面,如果还相同,就按名字的字典序先后排序。

这种多个条件的排序需要从外到里依次if判断是否相等,再从里到外依次return,比如最后比的是年龄,那么最先返回的就是年龄,依次类推,最后return的是颜值。

bool cmp(node x, node y)
{
    if (x.颜值 == y.颜值)
    {
        if (x.身高 == y.身高)
        {
            if (x.体重 == y.体重)
            {
                if (x.智商 == y.智商)
                {
                    if (x.情商 == y.情商)
                    {
                        return  x.年龄 < y.年龄;
                    }
                    return x.情商 > y.情商;
                }
                return x.智商 > y.智商;
            }
            return x.体重 > y.体重;
        }
        return x.身高 > y.身高;
    }
    return x.颜值 > y.颜值;
}

 

 

二分:

先来看两个二分的模板,以及向上取整还是向下取整,即这两个模板什么时候该用哪一个

 

两个模板的区别在于mid的取整(向上还是向下)
即mid =  l + r >> 1 还是 mid =  l + r + 1 >> 1;
取决于后两行的写法,而后两行的写法取决于题目分析的过程注意:关于上取整还是下取整:如果题目中要求最大值,就用上取整,如果要求最小值,就用下取整

模板一:(向下取整)
while(l < r)
{
    int mid = l + r >> 1; 
    if(check(mid)) r = mid;//右边界向下 此时mid向下取整(记忆方法)
    else l = mid + 1;
}

模板二:(向上取整)
while(l < r)
{
    int mid = l + r + 1 >> 1;
    if(check(mid)) l = mid;//左边界向上 此时mid向上取整(记忆方法)
    else r = mid - 1;
}

 

 

 

二分模板很简单,具体做题的时候关键的是依据题意求最大值还是最小值来判断用哪一个模板,以及依据题意写出判断mid时的check函数

然后是这个题:

CodeForces - 991C

题意:

有N个糖果,Vasya每天早起吃k个,Petya每天晚上吃10%。Vasya至少要吃一半,最小的k为多少?

思路:

二分找最优解,注意的点:long long ,奇数的情况 , n == 1的情况

然后本题的分析过程就是要求k的最小值,所以过程为向下取整

这题有点难,可以不死抠,主要是体会二分

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

long long n, ans;

bool check(long long mid)//模拟过程
{
    long long x = n,cnt = 0;
    while(x > 0)
    {
        cnt += min(x , mid);//x<mid不够吃,此时吃了x个
        x -= mid;
        x -= x / 10;
    }
    return cnt >= (n + 1) / 2;//注意奇数
}

int main()
{
    cin >> n;
    long long l = 1, r = n;
    while(l < r)
    {
        long long mid = l + r >> 1;
        if(check(mid)) ans = r = mid;
        else l = mid + 1;
    }
    if(n == 1) ans = 1;//n=1时因为l和r相同,所以ans最后为0,但ans实际上显然为最小为1,所以要特判
    cout << ans << endl; //或者ans初始值就设为1就不需要特判
    return 0;
}

 

posted @ 2021-03-17 10:22  彦辰kkkkk  阅读(138)  评论(0)    收藏  举报