今天先来复习昨天的老大难习题
835
不熟,晚上有时间再来一遍
# Trie树用来快速储存、查询字符串集合的
N =100010
son,cnt,idx = [[0]*26 for _ in range(N)], [0]*N,0
def insert(x):
global idx
p=0
for i in range(len(x)):
u = ord(x[i])-ord('a')
if not son[p][u]:
idx+=1
son[p][u] = idx
p = son[p][u]
cnt[p] += 1
def query(x):
global idx
p=0
for i in range(len(x)):
u = ord(x[i])-ord('a')
if not son[p][u]:
return 0
p = son[p][u]
return cnt[p]
n = int(input())
for _ in range(n):
op,x = input().split()
if op=='I':
insert(str(x))
else:
print(query(str(x)))
836并查集
还是比较丝滑的
# 并查集用来解决合并集合+查询两个数是否在同一个集合中
N = 100010
# 对于每个点来说,初始情况下,自己就是自己的父节点
p = [x for x in range(N)]
def find(x):
if p[x]!=x:
p[x] = find(p[x])
return p[x]
n,m = map(int, input().split())
for _ in range(m):
op,a,b = input().split()
if op == 'M':
p[find(int(a))] = find(int(b))
else:
if find(int(a))==find(int(b)):
print('Yes')
else:
print('No')
837
1、注意先加size,不然连上了,就是同一个祖宗节点,加也白加了
2、两个不在同一个集合内,才相连;在一个集合内,不需要操作
N = 100010
p = [x for x in range(N)]
size = [1]*N
def find(x):
if p[x]!=x:
p[x] = find(p[x])
return p[x]
n,m = map(int,input().split())
for _ in range(m):
op, *q = input().split()
if op == 'C':
a,b=int(q[0]),int(q[1])
if find(a)!=find(b):
size[find(b)] +=size[find(a)]
p[find(a)] = find(b)
elif op =='Q1':
a,b = map(int,q)
if find(a)==find(b):
print('Yes')
else:
print('No')
else:
a = int(q[0])
print(size[find(a)])
838
没那么难。
down()括号内是节点的编号
# 堆排序一般来解决排序问题,默认是小根堆
# 实现方法为一维数组
N = 100010
n,m = map(int,input().split())
heap = [0]*N
# 从1开始是因为从0开始不方便表示儿子节点
heap[1:n+1] = [int(x) for x in input().split()]
def down(u):
t = u
if 2*u<=n and heap[2*u]<heap[t]:
t = 2*u
if 2*u+1<=n and heap[2*u+1]<heap[t]:
t = 2*u+1
if t!=u:
heap[t],heap[u]=heap[u],heap[t]
down(t)
for i in range(int(n/2),0,-1):
down(i)
for _ in range(m):
print(heap[1], end=' ')
heap[1] = heap[n]
n-=1
down(1)
839
不是特别理解,但是能基本写出来了
问题还是挺多的
1\py中整除是//
2、删除和修改的时候记得down一遍,up一遍
3、注意输入进来的是在堆中的坐标,还是第几个输入的值。swap函数和h【】里面的都是堆中的坐标,注意转换。
N = 100010
h,ph,hp,idx,size=[0]*N,[0]*N,[0]*N,0,0
n = int(input())
def down(k):
t= k
if 2*k<=size and h[2*k]<h[t]:
t = 2*k
if 2*k+1 <= size and h[2*k+1]<h[t]:
t = 2*k+1
if t!= k:
swap(t,k)
down(t)
def up(k):
while k//2 and h[k//2]>h[k]:
swap(k//2,k)
k //=2
def swap(a,b):
ph[hp[a]],ph[hp[b]] = b,a
hp[a],hp[b] = hp[b],hp[a]
h[a],h[b] = h[b],h[a]
for _ in range(n):
op,*px = input().split()
if op == 'I':
x = int(px[0])
idx +=1
size+=1
h[size] = x
ph[idx] = size
hp[size] = idx
up(size)
elif op == 'PM':
print(h[1])
elif op=='DM':
swap(size,1)
size-=1
down(1)
elif op=='D':
k = ph[int(px[0])]
swap(size,k)
size-=1
down(k)
up(k)
else:
k,x = ph[int(px[0])],int(px[1])
h[k] = x
down(k)
up(k)
840
0x3f3f3f3f是一个很大的数,大于n可能出现的范围,所以当为这个数时,就是未被使用。是0f哦,不是of。
注意取mod的问题a-n*int(a/n)
k=mod(mod(x,N)+N,N)
然后对k+=1
# 哈希表主要用于把一个较大分散范围投射到娇小的范围
# 蹲坑法经验值Wie原来的两到三倍,然后是质数
N,null = 200003,0x3f3f3f3f
h = [null]*N
n = int(input())
def mod(a,n):
return a-n*int(a/n)
def find(x):
k = mod(mod(x,N)+N,N)
while h[k]!=null and h[k]!=x:
k+=1
if k==N:
k=0
return k
for _ in range(n):
op,px = input().split()
px = int(px)
k = find(px)
if op == 'I':
h[k] = px
else:
if h[k]==null:
print('No')
else:
print('Yes')
python中不存在负数取模的问题,也就是取的模就是正数,直接用%就可以、。
# 哈希表主要用于把一个较大分散范围投射到娇小的范围
# 蹲坑法经验值Wie原来的两到三倍,然后是质数
N,null = 200003,0x3f3f3f3f
h = [null]*N
n = int(input())
# def mod(a,n):
# return a-n*int(a/n)
def find(x):
k = x%N
while h[k]!=null and h[k]!=x:
k+=1
if k==N:
k=0
return k
for _ in range(n):
op,px = input().split()
px = int(px)
k = find(px)
if op == 'I':
h[k] = px
else:
if h[k]==null:
print('No')
else:
print('Yes')
843
getHash也要%Q,要不然估计数值太大了
另外,我感觉这里%Q并没有什么影响。
# 主要用于两个字符串是否相同
N = 100010
n,m = map(int,input().split())
def getHash(l,r):
return (h[r]-h[l-1]*p[r-l+1])%Q
P,Q=131,2**64
p,h = [0]*N,[0]*N
p[0]=1
string =' ' + str(input())
for i in range(1,n+1):
p[i] = (p[i-1]*P)%Q
h[i] = (h[i-1]*P + ord(string[i]))%Q
for _ in range(m):
l1,r1,l2,r2 = map(int,input().split())
if getHash(l1,r1)==getHash(l2,r2):
print('Yes')
else:
print('No')
还有一些之前的题没有做,先听课了,今天的任务是听完第三讲,听累了的时候再复习之前的题。
我的妈呀,3.1直接听自闭了哦~先写代码吧,心里有点怕怕,但是How hard could this be ??
842
N = 10
path, flag = [0]*N,[False]*N
def dfs(u):
# 其实没有n位,因为从0开始填,只不过u==n时,相当于填满了,直接输出就ok了
if u==n:
for i in range(n):
print(path[i],end=' ')
print()
return
for i in range(1,n+1):
if not flag[i]:
path[u]=i
flag[i]=True
dfs(u+1)
flag[i]=False
# path[u]不用恢复为0,因为会被覆盖
n = int(input())
dfs(0)
843
第一种顺序,遍历每列
N = 20
def dfs(u):
if u==n:
for i in range(n):
print("".join(grid[i]))
print()
return 0
for i in range(n):
if not col[i] and not dg[n+u-i] and not udg[u+i]:
col[i],dg[n+u-i],udg[u+i]= True,True,True
grid[u][i] = 'Q'
dfs(u+1)
grid[u][i]='.'
col[i],dg[n+u-i],udg[u+i]= False,False,False
n = int(input())
grid = [['.']*n for _ in range(n)]
col, dg, udg = [False]*N,[False]*N,[False]*N
dfs(0)N = 20
def dfs(u):
if u==n:
for i in range(n):
print("".join(grid[i]))
print()
return 0
for i in range(n):
if not col[i] and not dg[n+u-i] and not udg[u+i]:
col[i],dg[n+u-i],udg[u+i]= True,True,True
grid[u][i] = 'Q'
dfs(u+1)
grid[u][i]='.'
col[i],dg[n+u-i],udg[u+i]= False,False,False
n = int(input())
grid = [['.']*n for _ in range(n)]
col, dg, udg = [False]*N,[False]*N,[False]*N
dfs(0)
第二种顺序
好像也没有那么难,不过是找到一种顺序,然后就不断递推,恢复现场即可。【安慰一下自己】
这种python超时了
N = 20
def dfs(x,y,s):
if y==n:
x+=1
y=0
if x==n:
if s==n:
for i in range(n):
print(''.join(grid[i]))
print()
return 0
dfs(x,y+1,s)
if not row[x] and not col[y] and not dg[n+y-x] and not udg[x+y]:
row[x], col[y], dg[n+y-x], udg[x+y] = True, True, True, True
grid[x][y] = 'Q'
dfs(x,y+1,s+1)
grid[x][y] = '.'
row[x], col[y], dg[n + y - x], udg[x + y] = False, False, False, False
if __name__ == '__main__':
n = int(input())
grid = [['.']*n for _ in range(n)]
row, col, dg, udg = [False]*N, [False]*N, [False]*N, [False]*N
dfs(0,0,0)
844
1、这里使用了python内建的collections中的deque,可以用来表示队列和栈。
2、BFS的主要用途还是求最短的值。
大概模型是先初始进入队列
然后让t指向队头,根据队头进行扩展,放入队尾
直到队列为空,进行完毕
每个节点都有了各自的最短
# collections是Python内建的一个集合模块,提供了许多有用的集合类。
# deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:
from collections import deque
directions = [(1,0),(-1,0),(0,1),(0,-1)]
def bfs():
while q:
tmp = q.popleft()
for direction in directions:
x,y = tmp[0]+direction[0],tmp[1]+direction[1]
if x>=0 and x<n and y>=0 and y<m and g[x][y]==0 and d[x][y]==-1:
d[x][y]=d[tmp[0]][tmp[1]]+1
q.append((x,y))
return d[-1][-1]
n,m = map(int,input().split())
g,d,q = [],[[-1]*m for _ in range(n)],deque()
for _ in range(n):
g.append([int(x) for x in input().split()])
d[0][0]=0
q.append((0,0))
print(bfs())
846树的重心
感觉知乎大佬写的有点问题,应该先更新idx才对呀~以后还是多借鉴一下acwing上的叭
# 删掉树上的一点后,所剩子树的个数最大值 最小
N = 100010
ans = N
def add(a,b):
global idx
idx+=1
e[idx] = b
ne[idx] = h[a]
h[a] = idx
def dfs(u):
global ans
st[u] = True
sum,res = 1,0
i = h[u]
while i!=-1:
j = e[i]
if not st[j]:
s = dfs(j)
res = max(res,s)
sum +=s
i = ne[i]
res = max(res,n-sum)
ans = min(ans,res)
return sum
h,e,ne,idx = [-1]*N,[0]*2*N,[0]*2*N,0
st = [False]*N
n = int(input())
for i in range(n-1):
a,b = map(int,input().split())
add(a,b)
add(b,a)
dfs(1)
print(ans)
847图中点的层次
感觉像是简单的BFS搜索,没那么难,有一点点懂了
from collections import deque
N =100010
n,m = map(int, input().split())
h,e,ne,idx = [-1]*N, [0]*N,[0]*N,0
q,d = deque(),[-1]*N
q.append(1)
d[1] = 0
def add(a,b):
global idx
idx+=1
e[idx] = b
ne[idx] = h[a]
h[a] = idx
def bfs():
while q:
tmp = q.popleft()
i = h[tmp]
while i!=-1:
j = e[i]
if d[j]==-1:
d[j] = d[tmp]+1
q.append(j)
i = ne[i]
return d[n]
for _ in range(m):
a,b = map(int, input().split())
add(a,b)
print(bfs())
848 有向图的拓扑排序
有点懂了,但是不清楚如何保证每个j只会被append一次,因为d【j】只可可能为一次0?
所以要不然d【j】会被append因为==0;要不然不会,因为可能减少不到0
from collections import deque
N = 100010
h,e,ne,idx = [-1]*N,[0]*N,[0]*N,0
# d装的是入度
q,d,ans = deque(),[0]*N,[]
def insert(a,b):
global idx
idx += 1
e[idx] = b
ne[idx] = h[a]
h[a] = idx
def topsort():
for i in range(1,n+1):
if not d[i]:
q.append(i)
while q:
tmp = q.popleft()
ans.append(tmp)
i = h[tmp]
while i!=-1:
j = e[i]
d[j]-=1
if d[j]==0:
q.append(j)
i = ne[i]
return len(ans)==n
n,m = map(int,input().split())
for i in range(m):
a,b = map(int, input().split())
insert(a,b)
d[b]+=1
if topsort():
print(' '.join(map(str,ans)))
else:
print('-1')