第12周结(二分)

这周做题都是做的二分的题,感觉这一周还是蛮充实的。或许因为二分比dp简单吧,感觉学起来不是特别的费力。就简单说一说二分吧。
二分就是起到了简化代码时间复杂度的作用,通过把一个大的区间从中间分开分成两个小的区间,寻找所找的数在哪一个区间再进行,分区间直到找到这个数为止。
其实在做题中出现最多的就是循环不了,原因就是l和r可以相等,这就会陷入一个死循环,通常在这个时候,我就会挨个试一试,要不就在循环条件上把等于去掉,要不就在r或者l上加一减一。最后看一看答案是不是相同。通过几次的碰壁也是找到了几个不会“死”的代码

while(l<r)
   {
       int mid=(l+r)/2;
       if(num(mid)>(n-m))
        r=mid;
       else
        l=mid+1;
   }
   cout<<l<<endl 
while(l<=r)
     {
         int mid=(r+l)/2;
         if(num(mid)>m)
            r=mid-1;
         else //if(num(mid)<m)
         l=mid+1;

     }
cout<<r<<endl;

这里的输出可以根据答案的情况自行调整。
还有一种就是浮点数的了。

 while(r-l>1e-5)
        {
            double mid=(l+r)/2;
            if(num(mid))
            l=mid;
        else
            r=mid;

        }
cout<<r<<endl;

二分看起来简单,但是想一次通过就有点困难了,就这一周做的来说好想一次过的几乎没有。原因的就是一些细节上把控的不是很清晰。

做二分来说的话感觉最主要的就是找对l和r代表的什么意思,然后再根据题目进一步思考

下面说一说这周做的几个题吧:
B题感觉不像是二分的题,就是一个简单的map的使用,或许是可以用二分解,但是首先我首先想到的还是map练习B
D题就是给定n列数,每一列数有4行。从没列数中选取一个数让他们相加等于0,最后输出有几组相同的数。这个题因为课件上有一个类似的题型,就是把前两个列数两两组合的情况列出来(因为两两组合不会超时间,要是33或者44组合不会的话也可以)后面两列也是如此。最后通过选取后两列的数和前两列进行二分求出个数来就行。练习D
再就是E题了这个题就是让我们来求给定n个数中两两相减的绝对值的几个数里面的中位数。
这个题要是数量少的话直接排个序,用数组装上两两相减的值,再排个序,最后找到中位数就行了,可是给定的数值太大我们不得不考虑别的方法。这个题我们要求的是中位数,那么我们就先确定原始的l和r的值是多少。因为每一个数都是不相同的所以原始的l=1,r就是最大的数减去最小的数。知道区间了我们就来考虑着一个代码该怎么实现?当然显而易见我们就是来判断这个中位数在那个区间嘛,但是如何判断就是一个问题了。那该怎么判断?我们于是就来判断有多少个数小于mid,如果比m/2大则说明在mid~r,反之在 l~mid ,这个题到现在还是不是很麻烦,最麻烦的地方就是如何找到这些数而又不超时。那么在这里就用到了lower_bound。lower_bound的作用就是lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
还有一个就是upper_bound:
upper_bound的作用就是upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
求大于mid的代码如下:

bool num(int mid)
{
    ll lk=0;
    for(int i=1;i<=n;i++)
        lk+=(arr+n+1)-lower_bound(arr+i+1,arr+n+1,arr[i]+mid);
    if(lk<=m/2)
        return true;
    else
       return  false;
}

其实这些我全都完成以后,我提交了一次但是还是超时,我就抱着试一试的心态把老师课件上的输入的代码给写上了,在提交就神奇的通过了
输入代码如下:

inline int read(){
	register char ch=getchar();register int x=0;
	for(;ch<'0'||ch>'9';ch=getchar());
	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
	return x;
}

用法的就是 arr[i]=read();练习E
H和K是基本上一样的题给定n个数从中去除几个数从中求出两两相邻两数相减的最小值得最大值。这个题其实没啥说的就是求数中小于mid的个数,当时这个题做的时候就有点疑惑他为什么是

 for(int i=1;i<=n+1;i++)
        if(arr[i]-arr[j]<mid)
            sum++;
    else
        j=i;

之前做的题中if(arr[i]-arr[j]<mid)好像都是if(arr[i]-arr[j]>mid)然后又看了一看题目这个题是让我们求的是最大值。练习H 练习K
这就又有一个规律了:
二分中求最大值:
一般用cost+arr[i]<mid
而二分中求最小值:
一般是cost+arr[i]>mid
还有就是G题和W题,感觉这两个题也是蛮像的。就说一说W吧,每个人都分一样大的蛋糕,每个人只能分一块,这几说明不能从两个蛋糕中取求获得蛋糕的最大值,这个题唯一不好做的就是要用到上面的那个浮点型二分代码,上边的那个浮点的二分代码就是出自这个题答案的一部分。练习G 练习W
还有这周的最后一个题就是X题,这个题从中我学到了就是构造素数表,这个题难点也是这里吧,我朋友的代码如下:

bool ss(int n)
{
    for(int i=2;i<=sqrt(double(n));i++)
        if(n%i==0)
            return 0;
    return 1;
}
void b()
{
int l=1;
    for(int i=2;i<=1299709; i++)
        if(ss(i))
            p[l++]=i;
}

这周还打了一场cf上面的题,惨烈!!!就做了一个扣了71分那个题也整理了A. And Then There Were K在这儿
上面就是我这周做的所有的题,最后总结一下这周吧:
对二分有了初步的了解;
学会了upper_bound和lower_bound;
学会了构造素数表;
对位运算符也了解了一点。

  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晨晓翔同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值