2024 蓝桥杯模拟赛3(div1+div2)

P8834 [传智杯 #3 决赛] 序列

\(O(N^2)\)枚举

def read():
    return map(int, input().split())

n, k = read()
a = list(read())
res = 0

for i in range(n):
    for j in range(i):
        if a[i] * a[j] <= k:
            res += 1

print(res)

P8780 [蓝桥杯 2022 省 B] 刷题统计

数据很弱可以直接枚举

def read():
    return map(int, input().split())

a, b, n = read()
l = [a, a, a, a, a, b, b]
cnt, t, res = 0, 0, 0
while cnt < n:
    cnt += l[t]
    t = (t + 1) % 7
    res += 1
print(res)

当然比较保险的做法是算出一周的做题数,然后除一下

P8623 [蓝桥杯 2015 省 B] 移动距离

要把变换转换为坐标,然后计算曼哈顿距离。要注意偶数行的话要把纵坐标倒过来

def read():
    return map(int, input().split())

w, n, m = read()
n -= 1
m -= 1

nx, ny = n // w, n % w
if nx % 2 == 1:
    ny = w - 1 - ny

mx, my = m // w, m % w
if mx % 2 == 1:
    my = w - 1 - my
print(abs(nx - mx) + abs(ny - my))

P8738 [蓝桥杯 2020 国 C] 天干地支

直接打表,然后计算一下偏移量

tian = ["jia", "yi", "bing", "ding", "wu", "ji", "geng", "xin", "ren", "gui"]
di = ["zi", "chou", "yin", "mao", "chen", "si", "wu", "wei", "shen", "you", "xu", "hai"]
n = int(input())
print(tian[(n + 6) % 10], di[(n + 8) % 12], sep="")

P8635 [蓝桥杯 2016 省 AB] 四平方和

枚举三个平方数,然后计算第四个平方数,有解直接输出

import math

n = int(input())
m = int(math.sqrt(n))

for i in range(m):
    if i ** 2 > n:
        break
    a = i * i
    for j in range(i, m):
        if a + j ** 2 > n:
            break
        b = j ** 2
        for k in range(j, m):
            if a + b + k ** 2 > n:
                break
            c = k ** 2
            d = n - a - b - c
            if d < c:
                break
            l = int(math.sqrt(d))
            if l ** 2 == d:
                print(i, j, k, l)
                exit()

P8697 [蓝桥杯 2019 国 C] 最长子序列

直接贪心从前向后匹配即可,但是注意如果采用整行读入的做法,末尾疑似有多余的空格。

s, t = input(), input()
while s[-1] < 'A' or s[-1] > 'Z':
    s = s[0: -1]
while t[-1] < 'A' or t[-1] > 'Z':
    t = t[0: -1]

res = 0
for i in s:
    if res >= len(t):
        break
    if i == t[res]:
        res += 1
print(res)

P8654 [蓝桥杯 2017 国 C] 合根植物

这题并不需要转换坐标,直接采用并查集合并即可

class dsu:
    fa = list()

    def __init__(self, n):
        self.fa = [-1 for i in range(n + 1)]

    def find(self, n):
        if self.fa[n] < 0:
            return n
        self.fa[n] = self.find(self.fa[n])
        return self.fa[n]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.fa[x] > self.fa[y]:
            x, y = y, x
        self.fa[x] += self.fa[y]
        self.fa[y] = x

    def root(self, x):
        return x == self.find(x)


def read():
    return map(int, input().split())


n, m = read()
N = n * m
d = dsu(N)
k = int(input())
for i in range(k):
    a, b = read()
    d.union(a, b)

res = 0
for i in range(1, N + 1):
    res += d.root(i)
print(res)

P9421 [蓝桥杯 2023 国 B] 班级活动

首先统计每种人名使用的次数

如果一种名字使用次数等于2,则不用操作

如果一种名字使用次数大于2,则大于2的部分都需要改名,把这部分和记为\(res\)

如果一种名字使用次数小于2,也就是等于1,不一定需要改名,先把这部分的和记为\(ans\)

我们来考虑最优解是什么?最优解一定是把\(res\)部分的名字修改为\(ans\),然后把剩下的\(ans-res\)其中一半修改为另一半

所以答案就是\(res+\max(\frac{ans-res}{2} , 0)\)

def read():
    return map(int, input().split())


cnt = dict()
n = int(input())
for i in read():
    if i in cnt:
        cnt[i] += 1
    else:
        cnt[i] = 1
res, ans = 0, 0

for i in cnt.keys():
    if cnt[i] >= 2:
        res += cnt[i] - 2
    elif cnt[i] == 1:
        ans += 1

print(res + max(ans - res, 0) // 2)

P8604 [蓝桥杯 2013 国 C] 危险系数

因为点和边都不多,所以直接枚举删掉一个点,然后用并查集维护一下连通性,然后判断\(u,v\)是否联通,如果不连通,则删掉的点就是关键点

class dsu:
    fa = list()

    def __init__(self, n):
        self.fa = [-1 for i in range(n + 1)]

    def find(self, n):
        if self.fa[n] < 0:
            return n
        self.fa[n] = self.find(self.fa[n])
        return self.fa[n]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.fa[x] > self.fa[y]:
            x, y = y, x
        self.fa[x] += self.fa[y]
        self.fa[y] = x

    def root(self, x):
        return x == self.find(x)

    def same(self, x, y):
        x = self.find(x)
        y = self.find(y)
        return x == y


def read():
    return map(int, input().split())


n, m = read()
edge = [[] for i in range(m)]
for i in range(m):
    edge[i] = list(read())
u, v = read()
res = 0
for z in range(1, n + 1):
    if z == u or z == v:
        continue
    d = dsu(n)
    for it in edge:
        if it[0] == z or it[1] == z:
            continue
        d.union(it[0], it[1])
    if (d.same(u, v)):
        continue
    res += 1
print(res)

P8692 [蓝桥杯 2019 国 C] 数正方形

首先我们把点转换成段

image-20240226173257039.png

然后手画一下就会发现,有几段的矩形内部就有几种矩形,所以我们可以枚举一下矩形的大小,然后计算一下当前大小的矩形有多少个即可。

Mod = int(1e9 + 7)
n = int(input()) - 1
res = 0
for i in range(1, n + 1):
    res = (res + i * (n - i + 1) ** 2) % Mod
print(res)

P9232 [蓝桥杯 2023 省 A] 更小的数

40 分

首先最简单的方法就是暴力,直接枚举区间然后翻转比较一下

s = input()
n = len(s)
res = 0
for i in range(n):
    for j in range(i + 1, n):
        t = s[0: i] + s[i: j + 1][::-1] + s[j + 1:n]
        if t < s:
            res += 1
print(res)

100 分

正解是区间dp

其实我们还是要暴力的枚举区间,我们考虑如何快速判断区间是否合法

我们枚举的区间是\([l,r]\)

  1. 如果\(s_l > s_r\),则翻转后一定会更小
  2. 如果\(s_l<s_r\),则翻转后一定会更大
  3. 如果\(s_l=s_r\),则是否合法取决于\([l+1,r-1]\)

从小到达枚举区间,然后计算并统计合法区间数量即可

s = input()
n = len(s)
f = [[0 for i in range(n)] for j in range(n)]
res = 0
for len in range(1, n):
    l, r = 0, len
    while r < n:
        if s[l] > s[r]:
            f[l][r] = 1
        elif s[l] == s[r]:
            f[l][r] = f[l + 1][r - 1]
        res += f[l][r]
        l, r = l + 1, r + 1

print(res)

P8756 [蓝桥杯 2021 省 AB2] 国际象棋

这其实算是状压dp的模板题了

从左往右依次放置,因此只考虑右侧的列即可。

假设\((x,y)\)的位置有马,则\((x+2,y-1),(x-2)(y-1),(x+1,y-2),(x-1,y-2)\)都不能放置,因此我要知道当前列是否合法只需要知道上一列和上上一列即可。

因为行很少,我们可以用一个六位二进制数表示一列的情况。

设状态为\(f[i][j][a][b]\)表示前\(i\)列累计放置\(j\)个,且第\(i\)列状态为\(b\)、第\(i-1\)列状态为\(a\),这样只需枚举\(i,j\)以及最后三列\(a,b,c\)的状态即可判断是否可以进行转移。

为了方便计算,可以预处理val[x]表示每种状态下,这一列放置了多少个。

如果(b>>2)&c + (b<<2)&c == 0成立,则说明第\(i\)列和第\(i-1\)列不冲突。

如果(a>>1)&c + (a<<1)&c == 0成立,则说明第\(i\)列和第\(i-1\)列不冲突。

如果(b>>2)&a + (b<<2)&a == 0成立,则说明第\(i-2\)列和第\(i-1\)列不冲突。

如果val[a]+val[b]+val[c] <= j,则数量是合法的

如果上述都满足,则有转移f[i][j][b][c] += f[i-1][j-val[c]][a][b]

def read():
    return map(int, input().split())


n, m, k = read()
N = (1 << n)
Mod = int(1e9 + 7)

val = [0] * N
for i in range(N):
    x = i
    while x > 0:
        val[i] += x % 2
        x //= 2

if m == 1:
    res = 0
    for i in range(N):
        if val[i] == k:
            res += 1
    print(res)
    exit(0)

f = [[[[0 for i in range(N)] for i in range(N)] for i in range(k + 1)] for i in range(m)]

for a in range(N):
    if val[a] > k:
        continue
    for b in range(N):
        if val[a] + val[b] > k:
            continue
        if (a << 2) & b != 0 or (a >> 2) & b != 0:
            continue
        f[1][val[a] + val[b]][a][b] = 1

for i in range(2, m):
    for j in range(k + 1):
        for a in range(N):
            if val[a] > j:
                continue
            for b in range(N):
                if val[a] + val[b] > j:
                    continue
                if (a << 2) & b != 0 or (a >> 2) & b != 0:
                    continue
                for c in range(N):
                    if val[a] + val[b] + val[c] > j:
                        continue
                    if (b << 2) & c != 0 or (b >> 2) & c != 0:
                        continue
                    if (a << 1) & c != 0 or (a >> 1) & c != 0:
                        continue
                    f[i][j][b][c] = (f[i][j][b][c] + f[i - 1][j - val[c]][a][b]) % Mod
res = 0

for a in range(N):
    for b in range(N):
        res = (res + f[m - 1][k][a][b]) % Mod

print(res)

该说不说,python开数组还是挺抽象的

posted @ 2024-02-26 18:00  PHarr  阅读(115)  评论(0编辑  收藏  举报