位运算
方法一:
思路:在二进制表示中,1
的最低位是 1
,其余位都是 0
。==当一个数 i
和 1
进行“按位与”运算时,只有 i
的最低位是 1
时,结果才会是 1
,否则结果是 0
。==这是因为“按位与”运算的规则是,只有两个对应位都是 1
时,结果才是 1
,否则结果是 0
# 这个方法会超时,但是我觉得时间复杂度没啥区别
n = int(input())
L = [int(x) for x in input().split()]
def lowbit(i):
res = 0
while n:
if i & 1: # 检查二进制表示的最低位是否为1
res += 1
i+=1
return res
for i in L:
print(lowbit(i),end=" ")
方法二:
思路:在二进制表示中,-n
是 n
的二进制补码,即 n
的二进制表示的每一位取反后加 1
。因此,n & -n
的结果就是 n
的二进制表示中最低位的 1
。循环体中,首先计算 i
的二进制表示中最低位的 1
,然后从 i
中减去这个值,然后将 res
加 1
。这样,每次循环都会消除 i
的二进制表示中的一个 1
,直到 i
变为 0
,此时 res
就是 i
的二进制表示中 1
的个数。
n = int(input())
L = [int(x) for x in input().split()]
res = 0
def lowbit(n):
return n & -n # 保留最低位的1
for i in L:
while i:
i -= lowbit(i) # 每次减去最低位的1
res += 1
print(res,end=" ")
res = 0 # 重置res
离散化
这个题目为为什么要用离散化呢?
⚠️:因为存储的下标实在太大了,如果直接开这么大的数组,根本不现实,第二个原因,本文是数轴,要是采用下标的话,可能存在负值
开始我的写法:(不现实,且边界超出)
from sys import stdin
# 区间化
n, m = map(int, stdin.readline().split())
N = 2 * 10 ** 9 + 100
list_a = [0] * N
def interval_sum(n, m):
for i in range(n):
a, b = map(int, stdin.readline().split())
list_a[a] += b
for j in range(m):
sum = [0] * N
for i in range(1, N + 1):
sum[i] = sum[i - 1] + list_a[i]
l, r = map(int, stdin.readline().split())
print(sum[r] - sum[l - 1])
if __name__ == '__main__':
interval_sum(n, m)
**离散化的本质:**是映射,将间隔很大的点,映射到相邻的数组元素中。减少对空间的需求,也减少计算量
模版:
#把原区间序号离散化 IndexLst[i]的值代表原区间的序号,i代表离散化后的序号
#1.把添加,查询操作使用的所有序号记录下来,排序去重得到一个离散化后的区间
#2.按照离散化后的序号,进行 添加,求区间和的操作
n,m = map(int,input().split())
addNum = []
query = []
IndexLst = []
for i in range(n):
x,c = map(int,input().split())
addNum.append([x,c])
IndexLst.append(x)
for i in range(m):
l,r = map(int,input().split())
query.append([l,r])
IndexLst.append(l)
IndexLst.append(r)
#离散化操作
IndexLst.sort()
IndexLst = list(set(IndexLst))
def find(x):
l = 0
r = len(IndexLst)-1
while l<r:
mid = (l+r)>>1
if x<=IndexLst[mid]:r=mid
else:l=mid+1
return r+1 #离散化后的序号为1 —— len(IndexLst)-1
#注意nums序号从1到len-1
#s[0]=0 s[1] = nums[1]
nums=[0]*(len(IndexLst)+5)
s =[0]*(len(IndexLst)+5)
for x,c in addNum:
nums[find(x)]+=c
for i in range(1,len(IndexLst)+1):
s[i]=s[i-1]+nums[i]
for i in query:
l,r = find(i[0]),find(i[1])
print(s[r]-s[l-1])
区间合并
思路:
可以先按左端点排序,再维护一个区间,与后面一个个区间进行三种情况的比较,存储到数组里去
模版:
n = int(input())
arr = []
for i in range(n):
l,r = map(int,input().split())
arr.append((l,r)) # 用元组存储区间
arr.sort(key=lambda x:x[0]) # 按照区间的左端点排序
st = arr[0][0] # 区间的左端点
ed = arr[0][1] # 区间的右端点
num = 1
for i in range(1,n):
if arr[i][1] <= ed: # 如果当前区间的右端点小于等于ed,说明当前区间被包含在前一个区间中,直接跳过
continue
if arr[i][0] <= ed and arr[i][1] > ed: # 如果当前区间的左端点小于等于ed,但是右端点大于ed,说明两个区间有交集,更新ed
ed = arr[i][1]
if arr[i][0] > ed: # 如果当前区间的左端点大于ed,说明两个区间没有交集,更新st和ed,num+1
num += 1
st = arr[i][0]
ed = arr[i][1]
print(num)