首页 > 其他分享 >DAY6 位运算、离散化、区间和并

DAY6 位运算、离散化、区间和并

时间:2024-08-07 18:52:36浏览次数:11  
标签:10 运算 DAY6 存入 离散 int alls 区间 include

本文所有题目都可在acwing题库中找到,本文仅进行归纳整理

题目:acwing801

给定一个长度为 n的数列,请你求出数列中每个数的二进制表示中 1的个数。

输入格式

第一行包含整数 n。

第二行包含 n个整数,表示整个数列。

输出格式

共一行,包含 n个整数,其中的第 i个数表示数列中的第 i个数的二进制表示中 1的个数。

数据范围

1≤n≤100000
0≤数列中元素的值≤10^9

这道题当然可以从大到小2^n不断地遍历,然后把结果1/0存入数组,再遍历数组得到答案。

但是过于低效,本处采用位运算(与运算),将两个数的补码进行比较,只有都为1才为,否则为0。

#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N];
int lowbit(int x) {
	return x & (-x);
}
int main() {
	int n;
	cin >> n;
	while (n--) {
		int x; int res = 0;
		cin >> x;
		while (x) {
			x -= lowbit(x);
			res++;
		}
		cout << res << " ";
	}
}

本处代码中lowbit函数将x与(-x)进行位运算,可以得到源码中最低位的1,然后减去最低位的1(用res进行记录),不断重复就可以得到答案。

想要了解更多关于位运算的知识可以参考位运算:按位与、按位或、按位异或、按位左移、按位右移-CSDN博客

题目:acwing802

假定有一个无限长的数轴,数轴上每个坐标上的数都是 00。

现在,我们首先进行 n次操作,每次操作将某一位置 x上的数加 c。

接下来,进行 m次询问,每个询问包含两个整数 l和 r,你需要求出在区间 [l,r]之间的所有数的和。

输入格式

第一行包含两个整数 n和 m。

接下来 n行,每行包含两个整数 x和 c。

再接下来 m行,每行包含两个整数 l和 r。

输出格式

共 m行,每行输出一个询问中所求的区间内数字和。

数据范围

−10^9≤x≤10^9
1≤n,m≤10^5
−10^9≤l≤r≤10^9
−10000≤c≤10000

初步审题,其实会觉得和前文讲述的前缀和一致,但是细看之下其实还是有差异的。

本文中数据范围是−10^9≤x≤10^9,范围很庞大,但是实际上运用到的范围其实只占很小的一部分。我们可以将分散在数轴上的点聚合起来,采用离散化的思想(将多而稀的区间投影到小而密的区间)。

#include<iostream>
#include<vector>
#include<algorithm>
//离散区间和
using namespace std;
const int N = 1e6 + 10;
int a[N], s[N];
vector<int> alls;
typedef pair<int, int> PII;
vector<PII> add, query;
int find(int x){
	int l = 0,r = alls.size() - 1;
	while (l < r) {
		int mid = l + r >> 1;
		if (alls[mid] >= x) r = mid;
		else l = mid + 1;
	}
	return r + 1;
}//二分法查找
int main() {
	int n, m;
	cin >> n >> m;
	for (int i = 0; i < n; i++) {
		int x, c;//实际上的点坐标和加值
		cin >> x >> c;
		add.push_back({ x,c });//add存入(点,值)
		alls.push_back(x);//alls存入值
	}
	for (int i = 0; i < m; i++) {
		int l, r;//区间的始末位置
		cin >> l >> r;
		query.push_back({ l, r });//query存入区间的始末位置(坐标)
		alls.push_back(l);//alls存入区间始末位置
		alls.push_back(r);
	}
	sort(alls.begin(), alls.end());//升序排序
	alls.erase(unique(alls.begin(), alls.end()),alls.end());
	for (auto item : add) {
		int x = find(item.first);
		a[x] += item.second;
	}
	for (int i = 1; i <= alls.size(); i++) s[i] = s[i - 1] + a[i];
	for (auto item : query) {
		int l = find(item.first), r = find(item.second);
		cout << s[r] - s[l - 1] << endl;
	}
	return 0;
}

本处代码中,find()函数就是一个简单的二分法查找位置。用add中存入输入的点和值的点集,query存入输入区间的始末位置,alls存入输入的值和区间的始末位置。

在alls数组中和我们进行去重和排序。遍历add和query数组,采用前缀和的思想得到我们想要的答案。

alls数组去重排序的好处是提高遍历的效率,同时避免二分法查找出错(二分法查找必须包含某种性质,比如单调性)。

题目:acwing803

给定 n 个区间 [li,ri],要求合并所有有交集的区间。

注意如果在端点处相交,也算有交集。

输出合并完成后的区间个数。

例如:[1,3][1,3] 和 [2,6][2,6] 可以合并为一个区间 [1,6][1,6]。

输入格式

第一行包含整数 n。

接下来 n行,每行包含两个整数 l和 r。

输出格式

共一行,包含一个整数,表示合并区间完成后的区间个数。

数据范围

1≤n≤100000
−10^9≤li≤ri≤10^9

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int n, cnt = 0;
struct s {
	int l, r;
}a[100010],ans[100010];
int cmp(s a, s b) {
	if (a.l == b.l) return a.r < b.r;
	return a.l < b.l;
}
int main() {
	int n; cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i].l >> a[i].r;
}
	sort(a + 1, a + 1 + n, cmp);
	ans[++cnt] = a[1];
	for (int i = 2; i <= n; i++) {
		if (a[i].l <= ans[cnt].r) ans[cnt].r = max(ans[cnt].r, a[i].r);
		else ans[++cnt] = a[i];
	}
	cout << cnt << endl;
	return 0;
}

本题我找到了一种更加简单的算法,采用了结构体。

对数组中的元素用cmp函数进行排序,如果左端点相同就比较右端点大小,反之就比较左端点。

将排完序后的第一位存入ans,再进行比较迭代。排序的目的是为了使得a的区间范围比b更小或者更前。方便后面的筛查。如果a[i]的左端点比ans的右端点更小,那么更新ans的右端点;否则就存入a[i]。

标签:10,运算,DAY6,存入,离散,int,alls,区间,include
From: https://blog.csdn.net/2303_79012056/article/details/140944142

相关文章

  • 【数据结构与算法】删除循环队列中第k个元素的算法 C++实现(循环队列+模运算)
    数组a[MaxSize]用作一个循环队列,front指向循环队列中队头元素的前一个位置,rear指向队尾元素的位置。设计删除队列中第k个元素的算法。思路首先,判断kkk是否在有效范围内......
  • 【数据结构与算法】在循环队列中第k个元素之后插入元素的算法 C++实现(循环队列+模运算
    数组a[MaxSize]用作一个循环队列,front指向循环队列中队头元素的前一个位置,rear指向队尾元素的位置。设计在队列中第k个元素之后插入item的算法。思路首先,检查输入的位置k是否在合理的范围内,即1到queueSize(Q)(包含两端)。如果k在这个范围外,那么返回ERROR。然后,计......
  • 表达式相关(一)操作数栈、运算符栈
    NOIP2013普及组T2只有加法和乘法的表达式思考:使用tok来存放操作数或操作符(在编译器词法分析中称之为token,故简写为tok);输入只有一行可以用fgets,不知道题目给的输入文件有没有换行(fgets是会读入换行符的),所以还要加个判断,不然存放的时候会把换行符也当做运算符对于2+3+...的表达......
  • 运算符
    六、运算符算术运算符一元运算符++,--二元运算符+,-,*,/,%赋值运算符=扩展运算符+=,-=,*=,/=关系运算符>,<,>=,<=,==,!=,instanceof逻辑运算符&&,||,!,^位运算符&,|,^,~,>>,<<,>>>条件运算符?:字符串连接符+1、算数运算符1、一元运算符算数运算符中++,--......
  • 位运算符
    1.与(&)2.或(|)3.亦或(^)4.非(~)5.关于位运算的面试题问:如何用电脑将2乘8最快算出?6.左移右移的底层原理......
  • pytorch张量运算
    pytorch张量运算2.1数据操作深度学习落实到计算表现为矩阵计算pytorch、tensorflow中,计算的基本组件是Tensor。张量即多维数组,是矩阵计算的基本单元。Tensor:张量,一维张量即向量vector,二维张量即二维数组。张量是n维数组的统称python中有专门进行矩阵计算的库:numpy。pytor......
  • 逻辑运算符
    1.与(&&)两个变量必须一致(都是true),否则否则输出的就是false2.或(||)我或者你,其中一个变量是true,那么输出的值就一定是true3.非(!())把括号里的值进行反转,比如括号是真,则输出为假......
  • 代码随想录Day6
    454.四数相加Ⅱ给你四个整数数组nums1、nums2、nums3和nums4,数组长度都是n,请你计算有多少个元组(i,j,k,l)能满足:0<=i,j,k,l<nnums1[i]+nums2[j]+nums3[k]+nums4[l]==0示例1:输入:nums1=[1,2],nums2=[-2,-1],nums3=[-1,2],nums4=[0,2]输......
  • 监控系统原理揭秘-数据运算篇
    一、监控系统概览监控系统在现代技术环境中扮演着至关重要的角色。运营同学每天检查自己的活动数据,研发人员每天检查系统各项指标是否正常,这些工作都少不了监控系统的身影。通常来讲,监控系统包括数据采集、数据计算、数据存储、数据可视化及监控预警等功能。本文主要介绍数据计算......
  • 洛谷题单指南-前缀和差分与离散化-P1904 天际线
    原题链接:https://www.luogu.com.cn/problem/P1904题意解读:给出(左端点,高度,右端点)表示的若干建筑,要输出其轮廓,所谓轮廓就是每个点被覆盖的最高建筑的高度所描绘的线。解题思路:如果能计算每个点被覆盖的最高建筑的高度,用数组h[10005]保存,那么输出轮廓的过程只需要枚举每一个点,如......