20220820网易笔试题解
不是自己的场,所以不太认真,有问题的话大家可以随时私聊我。
T1
小红拿到了两个正整数a和b,她每次操作可以选择其中个正整数,删除个数位。例如,对于"1243"而言,进行一次操作可以生成"124"、"123"、 "143"或"243"。
小红希望最终a是b的倍数或者b是a的倍数。她想知道自己最少的操作次数是多少?
输入2个数a b,其中a,b<=1e9
输出最少的操作次数。
input: 1234 99 output: 2
思路:
1e9以内的数长度在10位以内,考虑某一个数字进行操作可以生成的所有的子项,顶多生成2^10=1024个。那么遍历两个数字可以生成的子集,总组合数不会超过1e6。
from collections import defaultdict
a,b=input().split()
inf=float('inf')
def getmap(s):
n=len(s)
mp=defaultdict(lambda:inf)
for i in range(1,1<<n):
price=0
cnt=0
for j in range(n):
if (i&(1<<j))==0:
price+=1
else:
cnt=cnt*10+int(s[j])
mp[cnt]=min(mp[cnt],price)
return mp
amap=getmap(a)
bmap=getmap(b)
ans=inf
for i,v1 in amap.items():
for j,v2 in bmap.items():
if i%j==0 or j%i==0:
ans=min(ans,v1+v2)
print(ans if ans != inf else -1) T2
嘤嘤觉得长城很美 ,特别是它的锯齿, 非常的优雅!
现在有一个数组,嘤嘤想把这个数组变成"长城",即对于"长城"中每 一个元 素左右两边的元素相等,并且与它不相等。例如[2,1,2,1,2,1,2),(1,9,1,9}是长城,{2,1,3,2,4,1,4,4,4,4)则不是长城。
你每次可以将一个元素加一,请问最少需要几次操作?
输入n和n个正整数。其中n<=2e5,ai<=1e9。
input: 6 1 1 4 5 1 4 output: 11
不难看出,最终序列中,奇数下标的所有数字都相同,偶数下标的数字也相同。
因为只能进行+1操作,那么数字只能上升到对应位置的最大值,统计最大值就好了。注意处理一下最大值相同的状况。
n=int(input())
a=list(map(int,input().split()))
mv=[0,0]
for i,v in enumerate(a):
mv[i&1]=max(mv[i&1],v)
ans=0
for i,v in enumerate(a):
ans+=mv[i&1]-v
if mv[0]==mv[1]:
ans+=n//2
print(ans) T3
小红拿到了一个仅由r'、'e'、'd'组成的字符串, 她定义一个字符'e'为"好e"当 且仅当这个'e'字符既和r相邻也和'd'相邻。 例如"reeder"只有一个"好e",前 两个'e'都不是"好e",只有第三个'e'是"好e"。
小红每次可以修改一个字符(可以将任意字符修改)为任意字符,即三种类型的字符可以相互修改) ,她希望最终"好e"的数量尽可能多。小红想知道,自己最少要修改多少次?
输入一个只有red三中字符的字符串,长度<2e5。
输出最小修改次数
input: derrd output: 1
这题太麻烦了不想写了……说下思路。
首先考虑奇数:目标字符串必然是redered 或者dereder。e的出现位置必然是奇数下标,偶数下标的值只有2种组成情况,看这2个组成的字符串和目标字符串的diff即可。
偶数比较麻烦。首先考虑偶数情况下的2种极端情况(我先将非e的字符写成x,以便统一):
- xexex*
- *xexex
为什么这两种特殊?因为里面有个,这个出现什么都可以,不用处理,相当于删了个字符用奇数的方案来处理。
然后考虑不能删除字符的情况。考虑到一个分割点,将字符串分割成:xex | xexex这种形态。为什么是这种形态呢?首先可以看到两侧的出现次数都是奇数,奇数的情况下组合序列必然唯一。
可以分割成多少种这种形态呢?可以枚举分割点,我们只需要使用一个前缀和和后缀和来维护前面的代价:
设定数组pre,pre[i]代表将[0..i]处理成形态为xexex的最小代价。
设定数组suf,suf[i]代表将[i..n)处理成形态为xexex的最小代价,注意这里是后缀,从后往前。
那么枚举所有的分割点(分割点前必然是偶数),ans=min(ans, pre[i]+suf[i+1])
注意我将原题中的字符转化为了x,x可能为r可能为d,所以一种xexexex其实是对应两种形态,注意处理。
因为不是自己的笔试……不想写了,太难了。
T4
小红拿到了一个数组 a1....an,她想知道有多少组(i, j, k)为"v三元组":第一个数和第三个数相等。且第一个数大于第二个数。
用数学语言描述:
1<=i<j<k<=n 且 ai==ak 且 ai>aj
输入n<1e5, ai<=1e9。
input: 6 3 1 3 4 3 4 output: 3
思路:
先考虑暴力:计算某一个位置的贡献,遍历所有它左侧左右比它大的数的出现次数,乘以所有它右侧比它大的数的出现次数。比如:2221222,1左侧有3个2,右侧有3个2,贡献将为9。
转化问题:对于一个位置,求一个数左侧和右侧出现相同的数字的组合。那么利用前缀和的思想,只需要看某个数字左侧有多少数字比它大,右侧有多少数字比它大,维护其出现次数的乘积就可以了。
假设当前遍历到了i位置,设定数组l,l[x]代表在[0..i)之中,x的出现次数。设定数组r,r[x]代表(i..n-1]中x的出现次数。那么再利用一个树状数组维护相同数字的乘积即可。
实现技巧:因为ai<=1e9,树状数组没法直接跑,要离散化
实现技巧:可以数字排倒序然后离散化,将问题转化为求比某数字小的组合。
n=int(input())
a=list(map(int,input().split()))
s=sorted(set(a),reverse=True)
mp={v:i for i,v in enumerate(s,start=1)}
a=[mp[i] for i in a]
maxv=100010
tree=[0]*maxv
l=[0]*100010
r=[0]*100010
def add(i,x):
while i<maxv:
tree[i]+=x
i+=i&-i
def get(i):
ans=0
while i:
ans+=tree[i]
i-=i&-i
return ans
for i in a:r[i]+=1
ans=0
for i in a:
ans+=get(i-1)
add(i,-l[i]*r[i])
l[i]+=1
r[i]-=1
add(i,l[i]*r[i])
print(ans) #网易##网易笔试##笔试##做完网易2023秋招笔试题,我裂开了#

顺丰集团工作强度 322人发布