课程总结第十二周-------二分小结

Posted 钟钟终

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了课程总结第十二周-------二分小结相关的知识,希望对你有一定的参考价值。

1.临近期末,要加快预习、复习和刷题。时间不太够,零碎的时间对于这些题目用处不大,总是断断续续的,所以特地把做题、总结的时间都集中在周六周日。
2.做下来,发现除了二分的题目,还有很多题目涉及到单调队列、单调栈、还有些树的知识,都很想花个时间去学。
3.再有对于题解。我其实非常喜欢在电脑前因为一段不明白的代码或者没想通的知识点坐上好几个小时,一直去想,然后想通的那种感觉。但是现在时间不太够,事情都很急。其实不太愿意去看题解,虽然最后的结果都是弄懂题目,但收获的快乐和对算法的掌握程度是不一样的。


二分
判断二分题目特征:
1.无论是二分查找,还是二分答案。都是在一个有序的题目的背景下,或者是通过对某一个条件来进行分类处理(比如对天数进行分类,对距离进行划分,直到满足题意,然后优化,得到最优解。有点说不明白)

2.二分上下界的确立,范围可以大,但不能小,只不过是多进行几次二分处理。但能准确把握上下界自然最好。

3.通过不断的枚举值,带入题目,然后更新上下界。问题点在于:已经查找到类似满足要求的答案,却并非最优,此时要根据题意处理,分成两类。
也就是边界问题

        if (check(mid))    r = mid;   
        else               l = mid + 1; (往左)

         if (check(mid))    l= mid;   
        else               r= mid - 1;   (往右)

对于浮点数的处理(double)
法一:
1.采用long long数组,对浮点数扩大相应倍数,当成整数处理。
2.答案除以相应倍数并且转化为(double)类型输出。
(这里,感觉有点问题,花了点时间还是没弄明白。思路肯定是对的,但用这个方法总是wr,样例也都过的,可能还是存在误差)
法二:(正常处理即可)
1.由于是浮点数,不会取整,自然需要考虑边界问题。
2.
虽然二分的次数变多了,但是答案保证了精度。

while(r-l>1e-6) //保证精度

G题收获:
先是题意看的就很模糊,看了好一会儿才明白。给定n天,构成m个集合,要求相对于每个集合的预算最少。
思路过程:
1.首先明白无法排序,对既定天数进行分组。
2.预算肯定从每天花费的最大值开始(下界确定)。自然想到确定上界,而每天的额度相加便可为上界。
3.进行二分处理。一直想的是最小的预算如何分配,忽略了要求分配的组数,所以一直没想明白。------>>>通过枚举钱来分组,如果所分组数大于m组,说明每月预算偏少,下节上移;如果所分组数小于m组,则说明预算变多,上界下移。(两方面考虑,组数才是重点)

本题答案对于取上界和下界:由于取最小值,因此取上界下移(r=mid-1

H题收获: (最小值–最大是多少)
给定一条河两岸的长度,n个石块,每个石块给定距离河一岸的长度,通过移动m个石块,在不同的方案中,求出牛跳过石头的最短距离的最大值。
思路过程:
1.n个石块对于河岸距离进行排序。(可以将河岸另一端看成一个石块,共计n+1个石块)
2.确定上下界。对于上下界的选取不必过于精确,程序对进行几次二分完全能处理。本题是对最小距离进行枚举,下界为0,上界为两岸长度。
3.通过最小距离来确定删除石块的个数。若当前石块的距离减去参考石块的距离小于枚举的最小值,则需要删除石块;若大于,则说明枚举的距离仍然是最小值,不需要进行操作。
4.如果删除石块的个数小于等于给定个数------>>>说明枚举的最小值可能偏小,下一种方案的最小值可能也满足,但会更大,下界上移;一直到删除石块的个数大于给定个数----->>>说明枚举的最小值过大,要删除很多石块,上界下移。
5.要求输出的是相邻两块石头个数距离最小的最大值,通过(4)的分析,确定为输出下界。

题K收获:
抛开题目背景。n个相对于起点的距离,要求m个点中任意两个点的中的最小距离要尽可能的大。
思路过程:
1.跟H题类似,相对着写代码就好。对每个点距离进行排序;枚举最小值,然后优化,查找到满足的最大值。
2.上下界的确立同样忽略,可以大但不能小。此题为安排牛所在位置,因此第一头牛所在位置固定,第二头牛的位置要对于枚举的最小值才能被安排。
3.如果被安排的牛的个数大于等于c---->>>表明最小值偏小,下界上移。由于题目要求“牛都被安排且每头牛的距离最小值尽可能的大”,下界为答案;否则表明枚举的距离过大,无法安排c头牛,上界下移。

题X收获:
找到一个包含给定数的素数区间,输出长度。
思路过程;
1.不难发现,若给定数本身为素数,区间便是这个数,输出0;若给定数为偶数,则在这个偶数两侧找到两个素数。
2.朴素方法自然也能做,但是问题是如何运用二分。最后发现复杂度并不高,用while循环向上找一个素数,向下找一个,最差即可。
素数筛法:(效率蛮高的)

const int maxn=1299750;
int a[maxn]={0};
void fun()
{
    for(int i=2;i*i<maxn;i++)
    {
        if(!a[i])
        {
            for(int j=i+i;j<maxn;j+=i)
            {
                a[j]=1;
            }
        }
    }
}

W题收获:
n块馅饼分给(f+1)个人,要求等分,求每个人所能分配的最大面积。(一块馅饼分配完后剩余部分不参与分配)
思路过程:(思路还是挺简单的)
1.按照老师上课所给思路,为了预防double精度不准的问题,将面积乘以1e7次方倍来控制精度,但就是过不了,总是wr,检查多遍,也没发现问题。最后还是采用double才ac的。(摸不着头脑)

2.扩大倍数的同时也将复杂度提高了。此外,由于每个人只能分配到一块馅饼,因此每人所分配到的面积不可能超过最大的那一块馅饼面积,上界的确定可减低复杂度。

S题收获:
一共有n个值,任取连续的几个,要求这个区间内值的和乘以区间内的最小值,得到的结果最大。
思路过程:
1.以每个值为基准,作为最小值,分别向左,向右查找比他大的值的下标位置。
2.由于不会使用单调栈,用的是朴素方法,只能勉强过。利用三次循环,这种方法我很早就掌握了,用的也渐渐熟练。但是要尽快学会单调栈,不然数据一强就会超时。
注意:题目中只说值为非负数,所以可能存在0。(就因为这个wr了好几次,心累)

for(int i=2;i<=n;i++)
    {
        while(l[i]>1 && a[l[i]-1]>=a[i])
            l[i]=l[l[i]-1];
    }

    for(int i=n-1;i>=1;i--)
    {
        while(r[i]<n && a[r[i]+1]>=a[i])
            r[i]=r[r[i]+1];
    }
    ans=-1;
    for(int i=1;i<=n;i++)
    {
        tmp=a[i]*(sum[r[i]]-sum[l[i]-1]);
   }

E题收获: (一个中位数概念的题目)
1.熟悉了 lower_bound(a,a+n,a[i]+mid)-a)up_bound(a,a+n,a[i]+mid)-a) 的用法。
前者:返回的是第一个大于等于a[i]+mid的下标;
后者:返回的是第一个大于a[i]+mid 的下标;
两者最差为a[i]+mid值的个数。
2.首先要枚举中位数的值。如果比他大的数比所有数的一半还要多,则说明取得中位数偏小,下界上移;如果取得数小于等于所有数的一半,说明中位数偏大,上界下移。
3.枚举的中位数,通过lower_bound对于每一个循环中的a[i]累加个数。
(明明一样的代码,有的却因为超时总过不了……)

int solve(int mid)
{
    int ans=0;
    for(int i=0;i<n;i++)
    {
        ans=ans+n-(lower_bound(a,a+n,a[i]+mid)-a);
    }
    return ans<=(m/2);
}

M题(做的太心急了,都没去分析题意,直接按照感觉写代码,自然wr了)

        if(m>=n)          //每个员工同一时间只能进行一项检查
            cout<<k<<endl;
        else               //每个医生同时只能检查一个员工
        {
            if((n*k)%m)
                cout<<n*k/m+1<<endl; //医生多一分钟做取余剩下的项目
            else 
                cout<<n*k/m<<endl;
        }

就在舒适圈里呆一会会儿,躺平躺平

以上是关于课程总结第十二周-------二分小结的主要内容,如果未能解决你的问题,请参考以下文章

第十二周课程总结

2019java第十二周课程总结

第十二周课程总结

第十二周课程总结

第十二周课程总结

第十二周课程总结