蓝桥杯2016初赛python题解

蓝桥杯2016初赛python题解,第1张

前言:除特殊说明外题解均可AC

蓝桥杯2016初赛
  • [蓝桥杯2016初赛]网友年龄
  • [蓝桥杯2016初赛]生日蜡烛
  • [蓝桥杯2016初赛]方格填数
  • [蓝桥杯2016初赛]寒假作业
  • [蓝桥杯2016初赛]剪邮票
  • [蓝桥杯2016初赛]四平方和
  • [蓝桥杯2016初赛]密码脱落
  • [蓝桥杯2016初赛]最大比例
  • [蓝桥杯2016初赛]煤球数目
  • [蓝桥杯2016初赛]凑算式
  • [蓝桥杯2016初赛]交换瓶子
  • [蓝桥杯2016初赛]报纸页数
  • [蓝桥杯2016初赛]平方怪圈
  • [蓝桥杯2016初赛]冰雹数
  • [蓝桥杯2016初赛]卡片换位
  • [蓝桥杯2016初赛]搭积木
  • [蓝桥杯2016初赛]取球博弈
  • [蓝桥杯2016初赛]压缩变换
  • [蓝桥杯2016初赛]有奖猜谜

[蓝桥杯2016初赛]网友年龄

思路:枚举网友的年龄情况,符合条件的就计数

cnt = 0
for age in range(10, 100):
    sonage = int(str(age)[-1::-1])
    if age - sonage == 27:
        cnt += 1
        #print(age, sonage)
print(cnt)

[蓝桥杯2016初赛]生日蜡烛

思路:除了要知道开始过生日的年龄,还要知道现在多少岁,枚举开始过生日和现在年龄,直接计算出一共吹了多少蜡烛,符合条件则输出即可。


for start in range(0, 100):
    for end in range(start, 100):
        tot = (start+end)*(end-start+1)//2
        if tot == 236:
            print(start)
[蓝桥杯2016初赛]方格填数

思路:直接爆搜就行,dfs枚举所有的情况,符合情况的计数就行。


N = 10
a = [[-2 for i in range(N)] for j in range(N)]
vis = [False for i in range(N)]#vis[i]表示数字i的使用情况
a[1][1] = -1#左上角
a[3][4] = -1#右下角

cnt = 0

def check(x, y, num):
    dx = [-1, 0, 1]#x的偏移
    dy = [-1, 0, 1]#y的偏移
    for i in dx:
        for j in dy:
            #X,Y表示相邻的位置
            X = x+i
            Y = y+j
            if X > 3 or X < 1 or Y < 1 or Y > 4:#越界
                continue
            if (X == 1 and Y == 1) or (X == 3 and Y == 4):#左下角和右下角
                continue
            if a[X][Y] == -1 or a[X][Y] == -2:#未填入数字的位置
                continue
            if X == x and Y == y:#正在被填入数字的位置
                continue
            if abs(a[X][Y] - num) == 1:#相邻位置的数字连续
                return False
    return True

def dfs(x, y):
    #X, Y是要填数字的格子
    Y = y + 1
    if Y > 4:
        Y = 1
        X = x+1#换行
    else:
        X = x
    if a[X][Y] == -1:#抵达右下角
        global cnt
        cnt += 1
        return 
    for i in range(10):#枚举0-9
        if (not vis[i]) and check(X, Y, i):#i没有被使用过并且i是合法的
            vis[i] = True
            a[X][Y] = i
            dfs(X, Y)
            a[X][Y] = -2
            vis[i] = False
dfs(1, 1)
print(cnt)

[蓝桥杯2016初赛]寒假作业

思路:枚举每个方块的数字,然后直接判断是否合法,合法就计数。


值得一提的是,等式右边的数不需要枚举,可以通过等式左边的数计算的出。


N = 10
a = [[-1 for i in range(N)] for j in range(N)]
vis = [False for i in range(20)]
cnt = 0

def dfs(x, y):
    if x == 4 and y == 3:#填好了最后一个方块
        global cnt
        cnt+=1
    newx = x
    newy = y#newx, newy表示需要填的方块位置
    newy += 1
    if newy > 3:
        newx += 1
        newy = 1
    if newy == 3:#如果需要填的方块在等式的右边
        if x == 1:
            num = a[x][1]+a[x][2]#直接计算出结果即可
            if num < 1 or num > 13:#超出范围
                return
            if vis[num]:#已经被使用过了
                return 
            a[newx][newy] = num
        elif x == 2:
            num = a[x][1]-a[x][2]
            if num < 1 or num > 13:
                return
            if vis[num]:
                return 
            a[newx][newy] = num
        elif x == 3:
            num = a[x][1]*a[x][2]
            if num < 1 or num > 13:
                return
            if vis[num]:
                return 
            a[newx][newy] = num
        else:
            num = a[x][1]//a[x][2]
            if num*a[x][2] != a[x][1]:#可以被除尽
                return 
            if num < 1 or num > 13:
                return
            if vis[num]:
                return 
            a[newx][newy] = num
        vis[num] = True
        dfs(newx, newy)
        vis[num] = False
    else:
        for i in range(1, 14):
            if vis[i]:
                continue
            a[newx][newy] = i
            vis[i] = True
            dfs(newx, newy)
            vis[i] = False
            
dfs(1, 0)
print(cnt)

[蓝桥杯2016初赛]剪邮票

思路:每一张邮票有两种状态,剪或者不剪。


于是我们可以枚举每个邮票的状态,然后在最后进行判断,是不是所有剪的邮票都是连接在一起的,如果是则记录。


import copy

a= [[0 for i in range(10)] for j in range(10)]#0表示没有被剪,1表示剪了
ans = 0

dx = [1, -1, 0, 0]
dy = [0, 0, 1, -1]

def check():
    #判断是否是只有一个连通块
    cnt = 0#连通块数量
    b = copy.deepcopy(a)
    for i in range(3):
        for j in range(4):
            if b[i][j] == 1:
                dfs1(i, j, b)
                cnt+=1
    return cnt == 1


def dfs1(x, y, b):
    b[x][y] = 0
    for i in range(4):
            X = x + dx[i]
            Y = y + dy[i]
            if X < 0 or X > 2 or Y < 0 or Y > 3:#超出范围
                continue
            if b[X][Y] == 1:
                dfs1(X, Y, b)

def dfs(num, cnt):
    if cnt == 5:#已经剪了五张邮票
        if check():#并且满足五张邮票连接在一起
            global ans
            ans += 1
        return
    if num == 12:#已经判断完最后一个位置的状态
        return 
    x = num//4#num对应的x坐标
    y = num%4#num对应的坐标
    for i in range(2):#每个位置有选和不选两种状态
        if i == 0:#不选
            dfs(num+1, cnt)
        else :#选
            a[x][y] = 1
            dfs(num+1, cnt+1)
            a[x][y] = 0
    

#从左到右,从上到下一次枚举每个位置的邮票能不能
dfs(0, 0)
print(ans)
[蓝桥杯2016初赛]四平方和

思路:如果使用暴力四层循环肯定会超时的,四层循环可以优化成三层循环,但是还是超时(c++不会超时就很……),于是想办法可不可以优化成两层循环。


仔细观察四平方的式子,左边是一对平方和,右边也是一对平方和,又考虑到N的范围不大,于是乎我们是不是可以直接预处理出所有平方和,然后我们只需要枚举a和b,通过查表直接得到c和d。


那么枚举a和b就是两层for循环了。


from math import sqrt
N = 5000010
ne = [-1 for i in range(N)]#查询表

#预处理出所有的平方和
for c in range(N):
    if c*c > N:#超出范围不考虑
        break
    for d in range(c, N):
        k = c*c + d*d
        if k > N:#超出范围不考虑
            break
        if ne[k] == -1:
            ne[k] = c#有两个数的平方和为k,且较小的数为c

while True:
    try:
        n = int(input())
        flag = 0
        for a in range(n+1):
            if a*a > n:
                break
            for b in range(a, n+1):
                k = a*a + b*b
                if k > n:
                    break
                if ne[n-k] != -1:
                    c = ne[n-k]#查表得出c
                    d = int(sqrt(n-k-c*c))#算出d
                    print(a, b, c, d)
                    flag = 1
                if flag:
                    break
            if flag:
                break
    except:
       break

[蓝桥杯2016初赛]密码脱落

前言:这题超时了,想不明白
思路:假定给我们的字符串是s1,那么我们如果可以求出s中的最长对称的子串s2(不要求连续),那么s1中除去字串的字符就是造成s不能对称的原因,那我们把这些字符继续在s1中补充,则不就得到了原字符串。


然后原字符串的长度减去s1的长度,应该也会等于s1的长度减去s2的长度。


那我们最终要求的就是s1中的最长对称子串的长度。



求s1的最长对称子串的长度,其实是等于s1与其反向字符串的最小公共子序列长度。


def lcs(s1, s2):
    f = [[0 for i in range(1010)] for j in range(1010)]
    for i in range(len(s1)):
        for j in range(len(s2)):
            if s1[i] == s2[j]:
                f[i+1][j+1] = f[i][j]+1
            else:
                f[i+1][j+1] = max(f[i+1][j], f[i][j+1])
    return f[len(s1)][len(s2)]

while True:
    s1 = input()
    s2 = s1[::-1]#反转字符串
    l = lcs(s1, s2)
    print(len(s1) - l)
    

[蓝桥杯2016初赛]最大比例 [蓝桥杯2016初赛]煤球数目

思路:直接找规律就很容易发现,设f[i]为第i层的数目,则有f[i]-f[i-1] = i。


tot = 0
st = 1
d = 2
for i in range(100):
    tot += st
    st += d
    d += 1
print(tot)

[蓝桥杯2016初赛]凑算式

思路:因为每个字母的数字不同,也就是将1到9的全排列分配下去。


如果不懂库函数里的内置函数可以自己直接暴力for循环。


import itertools
ls = [i for i in range(1, 10)]
cnt = 0
for num in itertools.permutations(ls):
    a,b,c,d,e,f,g,h,i = num
    DEF = d*100 + e*10 + f
    GHI = g*100 + h*10 + i
    tot = a + (b*GHI + c*DEF)/(c*GHI)
    if int(tot) == tot and tot == 10:
        cnt+=1
print(cnt)

[蓝桥杯2016初赛]交换瓶子

思路:观察每个位置的瓶子是否合法,如果不合法,则找到合法瓶子的位置,进行交换。


while True:
    n = int(input())
    a = list(map(int, input().split()))
    ne = [-1 for i in range(10010)]#ne[i]表示在a中值为i的下标
    cnt = 0
    for i in range(len(a)):
        ne[a[i]] = i
    for i in range(len(a)):
        if a[i] != i+1:
            temp = a[i]
            posi = ne[i+1]
            a[i], a[ne[i+1]] = a[ne[i+1]], a[i]
            ne[temp] = ne[i+1]
            ne[i+1]= i
            cnt+=1
            
    print(cnt)

[蓝桥杯2016初赛]报纸页数

思路:这题的难点在于看懂题目意思。




如果按照中间的折痕把这些书叠放在一起,那就成了三张纸,共有12页的报纸了。



题目意思理解了,然后根据对称性,很容易得到答案了。


print(1728 + 1125 - 1)#2852

[蓝桥杯2016初赛]平方怪圈

思路:随便找几个数,只要不是落入1的就可以,然后打印过程看看,找一下最大数直接输出就好了。


##x = 8
##while True:
##    strx = str(x)
##    tot = 0
##    for i in strx:
##        tot += int(i)**2
##    x = tot
##    print(tot)
print(145)

[蓝桥杯2016初赛]冰雹数

思路:证明放下面,想看思路。


首先我们只需要考虑n以内所有的奇数,偶数不需要考虑。


然后如果在变换的过程中碰到了我们已经算过的数可以直接跳过。


通过这两个优化基本就可以AC了。



证明:我们只需要证明偶数的变化过程中的最大值小于1到n中奇数变化过程中的最大值就行。


设a是1到n内的任意一个偶数,则在变化过程中a一直除2直到为一个奇数,a变化过程中的最大值有两种情况,只要这两种情况都小于等于1到n中某个奇数在雪花滚动的就行了。


a的最大值可能是它本身,也有可能是上面所说奇数的最大值。


奇数的最大值已经计算得出。


a-1为一个奇数,且a-1的第一次变化为3(a-1)就已经大于a了。


while True:
    n = int(input())
    ans = n#不大于n的最大高度
    for i in range(3, n+1, 2):
        t = i
        while t >= i:
            t = 3*t+1
            ans = max(ans, t)
            while not (t&1):
                t //= 2
    print(ans)
                

[蓝桥杯2016初赛]卡片换位

思路:确定初始状态和目标状态,从初始状态不断地移动空白块进行状态转移,直到到达目标状态。


这其实也就是一个bfs过程。


dx = [0, 0, -1, 1]
dy = [1, -1, 0, 0]

def bfs():
    d = {}
    d[now] = 0
    q = []
    q.append(now)
    while len(q):
        t = q[0]
        q.pop(0)
        if t.find('B') == Aindex and t.find('A') == Bindex:#交换了位置
            print(d[t])
            break

        idx = t.find(' ')
        #将一位坐标映射到二位位置上
        x = idx//3
        y = idx%3
        for i in range(4):
            X = x + dx[i]
            Y = y + dy[i]
            if X < 0 or X > 1 or Y < 0 or Y > 2:#超出范围
                continue
            sidx = X*3 + Y
            #将空白块进行移动,也就是交换字符串的两个字符
            if idx < sidx:
                newstr = t[0 : idx] + t[sidx] + t[idx + 1: sidx] + t[idx] + t[sidx+1 : ]
            else:
                newstr = t[0 : sidx] + t[idx] + t[sidx + 1: idx] + t[sidx] + t[idx+1 : ]
            if not (newstr in d):
                d[newstr] = d[t] + 1
                q.append(newstr)
while True:
    a = input()
    b = input()
    now = a+b
    Aindex = now.find('A')
    Bindex = now.find('B')
    #print(Aindex, Bindex)
    bfs()

[蓝桥杯2016初赛]搭积木

思路:爆搜就行了,发现蓝桥真的很喜欢考爆搜。


a = [[-1 for i in range(10)] for i in range(10)]
vis = [False for i in range(10)]#判断数字的使用情况

def dfs(x, y):
    if x == 4 and y == 4:#搭完了最后一个积木
        global cnt
        cnt += 1
    y += 1
    if y > x:
        y = 1
        x += 1
    for i in range(10):
        if vis[i]:#数字已经使用过
            continue
        #不满足上面的积木大于下面两个的积木
        if x-1 > 0 and y -1 > 0 and y-1 <= x-1 and i < a[x-1][y-1]:
            continue
        if x-1 > 0 and y > 0 and a[x-1][y] > i:
            continue
        a[x][y] = i
        vis[i] = True
        dfs(x, y)
        vis[i] = False

cnt = 0

dfs(1, 0)#自上而下,自左而右的进行搭积木

print(cnt)

[蓝桥杯2016初赛]取球博弈 [蓝桥杯2016初赛]压缩变换 [蓝桥杯2016初赛]有奖猜谜

思路:局数不多,其实直接用手算也行。


这里给出代码的算法

result = "vxvxvxvxvxvxvvx"
now = 777#剩余数
for i in result:
    if i == 'v':#赢了
        now <<= 1
    else :#输了
        now = 0 if now <= 555 else now-555
print(now)

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/570923.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-09
下一篇 2022-04-09

发表评论

登录后才能评论

评论列表(0条)

保存