首页 > 其他分享 >Living-Dream 系列笔记 第3期

Living-Dream 系列笔记 第3期

时间:2024-03-09 12:55:36浏览次数:19  
标签:Living int long while 笔记 ans using include Dream

本期主要讲解二分查找。

知识点

二分查找:

  • 思想:分治

  • 使用场景:在一个有序序列中,反复查找不同目标。

  • 时间复杂度:\(O(n \log n)\)。

实现:

  • 对数列排序;

  • 确定二分边界(通常为 L=最小下标-1R=最大下标+1);

  • 伪代码:

    int L=左边界-1,R=右边界+1;
    while(L+1<R){
       int mid=(L+R)>>1;
       if(目标在mid左侧) L=mid;
       else R=mid;
    }
    
  • 最后根据 LR 的位置进行特判(不必要)。

例题

T1

板子题。

若要找出第一次出现的编号,则在 a[mid]==x 时还需要向前寻找。

所以只需将伪代码改一下就行。

注意最后输出的编号应为 R,且需要特判 -1 的情况。

#include<bits/stdc++.h>
using namespace std;

int n,m,a[10000031];

int bs(int x){
	int l=0,r=n+1;
	while(l+1<r){
		int mid=(l+r)>>1;
		if(x<=a[mid]) r=mid;
		else l=mid;
	}
	if(a[r]==x) return r; 
	return -1;
}

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	while(m--){
		int x; cin>>x; cout<<bs(x)<<' ';
	} 
	return 0;
} 

T2

对学校数组排序,遍历 \(n\) 位学生,找出和当前学生最接近的,比他的估分大 / 小的分数线,对两种不满意值取 \(\min\),并加入答案,最后输出即可。

需要注意的是,因为我们的 LR 的下标是无效的,所以若某学生的分数足够低,就可能出现 L 不动的情况,从而导致输出无效结果。因此我们应当将第 \(0\) 所学校的分数线设为 \(- \infty\),从而避免此类情况。

Tips:开 long long

#include<bits/stdc++.h>
#define int long long
using namespace std;

int m,n,ans;
int a[100031],b[100031];

int bs1(int x){
	int l=0,r=m+1;
	while(l+1<r){
		int mid=(l+r)>>1;
		if(x<a[mid]) r=mid;
		else l=mid;
	}
	return a[l];
}
int bs2(int x){
	int l=0,r=m+1;
	while(l+1<r){
		int mid=(l+r)>>1;
		if(x<=a[mid]) r=mid;
		else l=mid;
	}
	return a[r];
}


signed main(){
	cin>>m>>n;
	for(int i=1;i<=m;i++) cin>>a[i];
	for(int i=1;i<=n;i++) cin>>b[i];
	a[0]=-1e9;
	sort(a+1,a+m+1);
	//cout<<bs(b[1]);
	
	for(int i=1;i<=n;i++){
		int x=bs1(b[i]),y=bs2(b[i]);
		ans+=min(abs(x-b[i]),abs(y-b[i]));
	}
	cout<<ans;
	
	return 0;
}

习题

T3

对于每个满足 \(1 \le i \le n\) 的 \(a_i\),二分查找 \(a\) 中第一个 \(\ge a_i+c\) 和 \(> a_i+c\) 的数,它们中间的就都是 \(a_i+c\),将其累加入 \(ans\) 中,最后输出 \(ans\) 即可。

如果你愿意,使用 STL lower_bound / upper_bound 将会快捷许多。

不开 long long \(92 \ pts\),警钟撅烂。

#include<bits/stdc++.h>
#define int long long
using namespace std;

int n,c,ans;
int a[200031];

int bs1(int x){
	int l=0,r=n+1;
	while(l+1<r){
		int mid=(l+r)>>1;
		if(x<=a[mid]) r=mid;
		else l=mid;
	}
	if(a[r]==x) return r; 
	return -1;
}
int bs2(int x){
	int l=0,r=n+1;
	while(l+1<r){
		int mid=(l+r)>>1;
		if(x<=a[mid]) r=mid;
		else l=mid;
	}
	if(a[l]==x) return l; 
	return -1;
}

signed main(){
    cin>>n>>c;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+n+1);
    
    for(int i=1;i<=n;i++)
        if(bs1(a[i]+c)!=-1&&bs2(a[i]+c)!=-1) 
            ans+=bs2(a[i]+c)-bs1(a[i]+c)+1;

    cout<<ans;
    return 0;
}

T4

和 T2 很像,只需要把那两个函数搬过来,在重写一下输入和输出即可。

我这里把两个函数合并到一块了。

#include<bits/stdc++.h>
#define int long long
using namespace std;

int m,n,ans;
int a[100031],b[100031];

int bs(int x){
	int l=0,r=n+1;
	while(l+1<r){
		int mid=(l+r)>>1;
		if(x<=a[mid]) r=mid;
		else l=mid;
	}
	if(abs(a[l]-x)<abs(a[r]-x)) return a[l];
    if(abs(a[l]-x)>abs(a[r]-x)) return a[r];
    if(abs(a[l]-x)==abs(a[r]-x)) return min(a[l],a[r]);
}

signed main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
        sort(a+1,a+n+1);
        a[0]=-1e9;
        
        cin>>m;
	for(int i=1,x;i<=m;i++) cin>>x,cout<<bs(x)<<'\n';
	return 0;
}

标签:Living,int,long,while,笔记,ans,using,include,Dream
From: https://www.cnblogs.com/XOF-0-0/p/18062548

相关文章

  • Living-Dream 系列笔记 第1期
    本期主要讲解模拟、枚举算法。例题T1简单模拟题。利用scanf/cin以int形式读入分和秒,并令秒循环累加,逢\(60\)归\(0\)并向分进\(1\),分则是逢\(24\)归\(0\)。在循环的过程中若分秒合起来是回文数字,则退出循环,按照题目格式输出当前时间。注意开始时间不算。#includ......
  • Living-Dream 系列笔记 第17期
    ProblemT1/*思路:分类讨论:若k=0,则输出x+1;若k>tot(x的位数),则输出1+k-tot个0+x;否则输出10^k+x。*/#include<bits/stdc++.h>usingnamespacestd;longlongk,x,tot,ans=1;//开longlongintmain(){ cin>>k>>x; if(k==0){cout<<x+1;return0;}//情况1......
  • Living-Dream 系列笔记 第14期
    本期主要讲解差分技巧。知识点我们令原数组为\(a_i\),则当且仅当\(d_i=a_i-a_{i-1}\)时,我们称\(d_i\)是\(a_i\)的差分数组。特别的,\(d_1=0\),\(d_{n+1}=-n\)。差分数组\(d_i\)有以下三个性质:\(d_i\)的前缀和数组为\(a_i\)。将\(a_{L\simR}\)这个区间统一加......
  • Living-Dream 系列笔记 第15期
    模拟赛爆炸祭。T1把所有连通块依次求出,若某个连通块的数量已经出现过,则说明它与以前的连通块属于同一星系,直接将星系大小加上连通块大小并取\(\max\);否则将星系数量\(+1\)。#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;intn,m;intans=-1e9,num,......
  • Living-Dream 系列笔记 第11期
    本期主要讲解与上期相同内容(雾。例题T1在整个矩阵外加一圈\(0\),使得包围圈外的\(0\)形成一整个连通块。求出这个连通块并标记为\(1\),然后输出即可。#include<bits/stdc++.h>usingnamespacestd;intn;intdx[]={-1,0,1,0},dy[]={0,1,0,-1};inta[31][31],g[31][31];......
  • Living-Dream 系列笔记 第12期
    本期主要讲解一维前缀和技巧。知识点我们令\(a_i\)表示原数组的第\(i\)个元素,则\(sum_i\)表示\(a_i\)前\(i\)个元素之和,即:\[sum_i=\sum^{i}_{j=1}a_j\]我们知道,\(a\)数组前\(i\)个元素的和\(=\)前\(i-1\)个元素的和\(+a_i\)。于是便可得到\(sum\)数组的......
  • Living-Dream 系列笔记 第13期
    本期主要讲解二维前缀和。知识点我们令\(a_{i,j}\)表示原数组,则\(sum_{i,j}\)为\(a\)的二维前缀和数组。根据容斥原理,得到递推式:\[sum_{i,j}=sum_{i-1,j}+sum_{i,j-1}-sum_{i-1,j-1}+a_{i,j}\]二维前缀和适用于求静态矩阵的子矩阵元素和。若我需要求一个左上角坐标为......
  • Living-Dream 系列笔记 第10期
    本期主要讲解进阶\(\text{DFS}\)。知识点\(\text{DFS}\)求解连通块问题:定义:若一个点集中的所有点都能互达,且与集合外的点无法互达,则称此点集为一个连通块。考查方式:求连通块数量/大小/周长。例题T1在\(\text{DFS}\)函数中传入参数\(x\)和\(str\),分别表示......
  • Living-Dream 系列笔记 第8期
    本期主要讲解的与上期相同。例题T1上课的时候调这个题感觉要吐了\(qwq\)。。。首先读入\(n\)行字符串,可以采取忽略中间无关单词的方式来直接读取\(X\)和\(Y\)。将所有名字存入\(a\)数组,对\(a\)数组按字典序排序后就可以开始\(\text{DFS}\)了,这里建议使用next_pr......
  • Living-Dream 系列笔记 第9期
    模拟赛掉大分(悲T1板子,不讲。T2首先很明显这题是个去重全排列。和模板的区别就是加了一个\(sum\)参数记录目前已经放了几个苹果。当\(x=n+1\)时若\(sum=m\),则更新答案。同时加入一个剪枝:若在搜索过程中\(sum>m\),则直接return结束搜索。#include<bits/stdc++.h>usi......