蓝桥杯备赛(四)-枚举、模拟和排序

蓝桥杯备赛(四)-枚举、模拟和排序

概念

这不算算法,主要是一种思维方式。通过将现实问题转换为计算机进行推导的问题。

实例

Q1

连号区间数(原题链接)

A1

该题很典型的可以通过枚举进行,我们首先固定左顶点,然后遍历右顶点,逐渐判断最大值-最小值==l-r(为啥不用+1,自己领会)。
代码如下:

n=int(input())
cnt=0
list_=list(map(int,input().split(' ')))
for i in range(len(list_)):
    max_=list_[i]
    min_=list_[i]
    for j in range(i,len(list_)):#本身也是一个结果
        if max_<list_[j]:max_=list_[j]
        if min_>list_[j]:min_=list_[j]
        if max_-min_==j-i:
            cnt+=1
            #print(list_[i],list_[j])
print(cnt)

Q2

递增三元组(原题链接)

A2

二分查找+排序即可
代码如下:

def get_low(x):
    l=-1
    r=n
    while l+1!=r:
        mid=l+r>>1
        if a_lst[mid]<x:
            l=mid
        else:
            r=mid
    return l+1
def get_up(x):
    l=-1
    r=n
    while l+1!=r:
        mid=l+r>>1
        if c_lst[mid]>x:
            r=mid
        else:
            l=mid
    return n-r
n=int(input())
a_lst=sorted(list(map(int,input().split())))
b_lst=sorted(list(map(int,input().split())))
c_lst=sorted(list(map(int,input().split())))
res=0
for x in b_lst:
    #print(get_up(x))
    res+=get_low(x)*get_up(x)
print(res)

另一种为前缀和做法。

n=int(input())
a_list=list(map(int,input().split(' ')))
b_list=list(map(int,input().split(' ')))
c_list=list(map(int,input().split(' ')))
res=0
ant=[0 for i in range(100001)]
cnt=[0 for i in range(100001)]
as_=[0 for i in range(100001)]
cs_=[0 for i in range(100001)]
for i in range(n):
    ant[a_list[i]]+=1
    cnt[c_list[i]]+=1
as_[0]=ant[0]
cs_[0]=cnt[0]
for i in range(1,100001):
    as_[i]=ant[i]+as_[i-1]
    cs_[i]=cnt[i]+cs_[i-1]
for b in b_list:
    if b==0:
        pass
    else:
        res+=as_[b-1]*(n-cs_[b])
print(res)
#采取前缀和需要特判b-1,若b小于0,则变为了-1,就错了!!!

Q3

特别数的和(原题链接)

A3

代码如下:

n=int(input())
sum_=0
def check(i):
    while i:
        t=i%10
        i//=10
        if t==2 or t==0 or t==1 or t==9:
            return True
    return False
for i in range(1,n+1):
    if check(i):
        sum_+=i
print(sum_)

Q4

错误票据(原题链接)

A4

通过构造出现次数数组来计算,枚举。
代码如下:

n=int(input())
t=n
cnt=[0 for _ in range(100001)]
max_=0
min_=100000
while t:
    a_list=list(map(int,input().split(' ')))
    for a in a_list:
        cnt[a]+=1
        max_=max(max_,a)
        min_=min(min_,a)
    t-=1
for i in range(min_,max_+1):
    if cnt[i]==0:
        m=i
    if cnt[i]==2:
        n=i
print('%d %d'%(m,n))

通过快排来进行推导也不错(需要注意remove的使用以及列表中in的使用)

n=int(input())
c=0
L=[]
while c<n:
    s=input().split()
    for i in s:
        L.append(int(i))
    c+=1
L.sort()
for i in range(L[0],L[-1]+1):
    if i in L:
        L.remove(i)
        if i in L:
            n=i
    else:
        m=i
print('%d %d'%(m,n))

使用collections模块的counter

import collections
n=int(input())
nums=[]
for i in range(n):
    nums+=list(map(int,input().split(' ')))
counter=collections.Counter(nums)
#python中的counter容器
#记录其中出现次数最多的,这里就是重复出现的
rep=counter.most_common(1)[0][0]
nums.remove(rep)
los=(max(nums)+1-min(nums))*(max(nums)+min(nums))/2-sum(nums)
print('%d %d'%(rep,los))

Q5

回文日期(原题链接)

A5

我们可以check前四位数字,然后填充后四位,判断其是否是合法日期且是否在范围内即可
代码如下:

start_data=int(input())
end_data=int(input())
cnt=0
mouth_list=[31,28,31,30,31,30,31,31,30,31,30,31]
def check(i):
    year=i
    mouth=(i%10)*10+(i//10)%10
    day=((i//100)%10)*10+i//1000
    num=year*10000+mouth*100+day
    #print('%d %d %d'%(year,mouth,day))
    if (year==0)|(day==0)|(mouth==0):
        return False
    if ((year%4==0)&(year%100!=0))|(year%400==0):
        #闰年
        if mouth==2:
            if day<30:
                if num>=start_data&num<=end_data:
                    return True
        else:
            if mouth<13:
                if day<=mouth_list[mouth-1]:
                    if num>=start_data&num<=end_data:
                        return True
    else:
        if mouth<13:
            if day<=mouth_list[mouth-1]:
                    if (num>=start_data)&(num<=end_data):
                        return True
    return False
start=start_data//10000
end=end_data//10000
for i in range(start,end+1):
    if check(i):
        cnt+=1
print(cnt)

Q6

移动距离(原题链接)

A6

看代码即可,蛇形移动问题。
代码如下:

w,m,n=map(int,input().split())
def get_pos(x):
    x-=1
    i=x//w
    if i%2:
        j=x%w
    else:
        j=w-1-x%w
    return i,j
i1,j1=get_pos(m)
i2,j2=get_pos(n)
print(abs(i1-i2)+abs(j1-j2))

Q7

日期问题(原题链接)

A7

看代码自行理解
代码如下:

def check(yy,mm,dd):
    mouth_lst=[31,28,31,30,31,30,31,31,30,31,30,31]
    if yy>=60:
        yy+=1900
    else:
        yy+=2000
    if yy%400==0 or (yy%100!=0 and yy%4==0):
        mouth_lst[1]=29
    if mm>0 and mm<13:
        if 0<dd<=mouth_lst[mm-1]:
            return yy*10000+mm*100+dd
    return 0
aa,bb,cc=map(int,input().split('/'))
res=[]
if check(aa,bb,cc)!=0:
    res.append(check(aa,bb,cc))
if check(cc,aa,bb)!=0:
    res.append(check(cc,aa,bb))
if check(cc,bb,aa)!=0:
    res.append(check(cc,bb,aa))
res=set(res)
res.sort()

for i in res:
    print('%d-%02d-%02d'%(i//10000,(i//100)%100,i%100))



Q8

航班问题(原题链接)

A8

学学别人漂亮的代码,思维碾压。需要注意的是,时差可以来回两次抵消掉了。同时我们可以注意,我们可以先统一为秒制,方便计算。
代码如下:

t=int(input())
for _ in range(t):
    ans=0
    for __ in range(2):
        a=input().split()
        for i in range(len(a)):
            if i==2:ans+=int(a[i][2])*24*3600
            else:
                b=list(map(int,a[i].split(':')))
                ans+=pow(-1,i+1)*(b[0]*3600+b[1]*60+b[2])
    print(format("%02d:%02d:%02d"%( ans//7200, ans%(7200)//120, ans%120//2 ) ) )
#漂亮简洁,学着点

Q9

外卖店优先级(原题链接

A9

该题主要采取模拟的方式来进行,需要注意对于边界的考虑以及何时出优先队列,需要考虑清楚。
代码如下:

n,m,t=map(int,input().split())
shop_dict={}
cnt=0
for _ in range(m):
    t_,id=map(int,input().split())
    if id in shop_dict:
        shop_dict[id].append(t_)
    else:
        shop_dict.setdefault(id,[t_])
for _,tic_lst in shop_dict.items():
    if len(tic_lst)<3:
        continue
    flag=0
    score=2
    tic_lst.sort()
    for i in range(1,len(tic_lst)):
        if tic_lst[i]!=tic_lst[i-1]:
            score-=tic_lst[i]-tic_lst[i-1]-1
        if score<0:
            score=0
        if score<=3:
            flag=0
        score+=2
        if score>5:
            flag=1
    if flag and score-(t-tic_lst[-1])>3:
        cnt+=1
print(cnt)

另一种解法:

[n,m,t]=list(map(int,input().split(' ')))
cnt=0
flag=False
T=m
tic_list=[]
score=2
while T:
    tic_list.append(list(map(int,input().split()))[::-1])
    T-=1
#按照店铺排序
tic_list.sort()#默认是升序的
tic_list.append([0,0])
for i in range(1,m+1):
    if tic_list[i][0]!=tic_list[i-1][0]:#不是同一个商家
        #此时就需要计算上一个商家是否在优先缓存中了
        if flag and (score-(t-tic_list[i-1][1])>3):cnt+=1
        flag=False
        score=2#恢复原状
    else:
        #同一个商家,更新score并且判断是否在内
        if tic_list[i][1]!=tic_list[i-1][1]:
            score-=tic_list[i][1]-tic_list[i-1][1]-1
        if score<0:score=0
        if score<=3:flag=False
        score+=2
        if score>5:flag=True
print(cnt)

Q10

逆序对的数量(原题链接)

A10

该题主要在于灵活运用归并排序的思维进行计算。
计算逆序对的数量(序列):

  1. 递归算左边的;
  2. 递归算右边的;
  3. 算一个左一个右的;
  4. 把他们加到到一起。
    代码如下:
def merge_sort(nums):
    if len(nums)<=1:return 0
    mid=len(nums)//2
    L=nums[:mid]
    R=nums[mid:]
    ans=merge_sort(L)+merge_sort(R)
    #归并的过程
    i=j=k=0
    while i<len(L) and j<len(R):
        if L[i]<=R[j]:
            nums[k]=L[i]
            k+=1
            i+=1
        else:
            nums[k]=R[j]
            ans+=len(L)-i
            k+=1
            j+=1
    while i <len(L):
        nums[k]=L[i]
        k+=1
        i+=1
    while j <len(R):
        nums[k]=R[j]
        k+=1
        j+=1    
    return ans
if __name__ == "__main__":
    n = int(input())
    nums = list(map(int, input().split())) 
    print(merge_sort(nums))

总结

男的一批。要灵活运用python各种自带模块,同时需要关注各种排序算法的使用,以及各种思维的运用,如何简化问题。

你可能感兴趣的:(python,数据结构与算法,蓝桥杯,算法)