2024天梯赛选拔赛补题笔记

3/21仅供参考,题目无法提交

3/22补题入口开放

只因你太美 数学、思维

设有一个正整数 a。我们将 a 分解为n个质数的乘积。
令 a=p1​×p2​×p3​×⋯×pn​,其中每个 pi​ 均为质数。
当且仅当 pi​ 都是奇数时,我们称 a 为只因数。对于给定的一个正整数m,如果m为只因数,输出“只因你太美”的英文Just because you are so beautiful,接着进行判断,若该只因数最大的分解结果就是该只因数本身,输出!!!,否则输出!。若m不是只因数,则只输出一行Just because you are not beautiful

输入格式:

第一行是一个整数,表示数据组数 T。
接下来 T 行,每行一个整数,表示一组数据的 n。

输出格式:

对每组数据,如果 n 是『只因数』,请输出Just because you are so beautiful,若该只因数最大的分解结果就是该只因数本身,输出!!!,否则输出!。若m不是只因数,则只输出一行Just because you are not beautiful

输入样例:

在这里给出一组输入。例如:

5
2
3
4
6
9

输出样例:

Just because you are not beautiful
Just because you are so beautiful!!!
Just because you are not beautiful
Just because you are not beautiful
Just because you are so beautiful!

Hint1

质数就是素数,2,3,5,7...,2是其中唯一偶数,若2为其质因数,则其为偶数

Hint2

若该只因数最大的分解结果就是该只因数本身,输出!!!

素数的最大分解结果是什么?

Code

n = int(input())
def isprime(x):
    res = 2
    while res * res <= x:
        if x % res == 0:
            return 0
        res +=1
    return 1
for i in range(n):
    t = int(input())
    if t % 2 == 0:
        print("Just because you are not beautiful")
    elif isprime(t):
        print("Just because you are so beautiful!!!")
    else:
        print("Just because you are so beautiful!")

卡路里 贪心

冰箱里有n种食物,第i种食物有mi​ cal(卡路里),以及含有vi​营养物质。计算鸭制定了未来k天减肥计划,第j天最多摄入cj​ cal(卡路里),并且每天只吃一种食物。

问:计算鸭可以摄入营养物质的最大值是多少。

输入格式:

输入的第一行给出两个整数n,k,含义如题意所示;

接下来n行,每行两个整数mi​,vi​,含义如题意所示;

接下来k行,每行一个整数cj​,含义如题意所示;

1≤n,k≤3×105

1≤mi​,vi​≤106

1≤cj​≤108

输出格式:

输出一个整数——表示计算鸭可以摄入的最多营养物质的含量。

输入样例:

3 2
1 65
5 23
2 99
10
2

输出样例:

164

 贪心得20分,食物按照营养降序sort,减肥计划升序sort,两个点超时一个点爆内存

仍待解决

Code

标程

#include<cstdio>
#include<algorithm>
#include<queue>
#define MAXN 300003
using namespace std;
int n, k;
struct BREAD
{
	int m, v;
} a[MAXN];
bool cmp(BREAD x, BREAD y)
{
	return x.m < y.m || (x.m == y.m && x.v < y.v);
}
priority_queue<int> Q;
int c[MAXN];
int main()
{
	scanf("%d%d", &n, &k);
	for (int i = 1; i <= n; i++) 
		scanf("%d%d", &a[i].m, &a[i].v);
	for (int i = 1; i <= k; i++)
		scanf("%d", &c[i]);
	
	sort(c + 1, c + k + 1);
	
	sort(a + 1, a + n + 1, cmp);
	
	long long ans = 0;
	int j = 1;
	for (int i = 1; i <= k; i++)
	{
		for (; j <= n && a[j].m <= c[i]; j++)
			Q.push(a[j].v);
		
		if (!Q.empty())
			ans += Q.top(), Q.pop();
	}
	printf("%lld\n", ans);
	return 0;
}

py最后一个点过不了

import heapq
n, m = map(int,input().split())
food = []
for i in range(n):
    food.append(list(map(int,input().split())))
c = []
for i in range(m):
    c.append(int(input()))
c = sorted(c)
food = sorted(food, key=lambda x:(x[0],x[1]))
pos,ans = 0,0
q = []
for i in range(m):
    while pos<n and food[pos][0] <= c[i]:
        heapq.heappush(q,-(food[pos][1]))
        pos+=1
    if q:
        ans += -heapq.heappop(q)
print(ans)

TT

特别感谢古大佬和出题大佬imtian答疑OrzOrz

小猫爬山 搜索

参考小猫爬山(排序、递归)_小猫爬山算法题-CSDN博客

Freda 和 Rainbow 饲养了 N 只小猫,这天,小猫们要去爬山。经历了千辛万苦,小猫们终于爬上了山顶,但是疲倦的它们再也不想徒步走下山了。

Freda 和 Rainbow 只好花钱让它们坐索道下山。索道上的缆车最大承重量为 W,而 N 只小猫的重量分别是 C1​、C2​ …… CN​。当然,每辆缆车上的小猫的重量之和不能超过 W。每租用一辆缆车,Freda 和 Rainbow 就要付 1 元,所以他们想知道,最少需要付多少元才能把这 N 只小猫都运送下山?。

输入格式:

输入文件共 1+N 行。每行中两个数之间用一个空格隔开。

第一行包含两个用空格隔开的整数,N 和 W。

接下来 N 行每行一个整数,其中第 i+1 行的整数表示第 i 只小猫的重量 Ci​。

输出格式:

输出共 1 行,输出一个整数,最少需要多少元,也就是最少需要多少辆缆车。

输入样例:

5 1996
1
2
1994
12
29

输出样例:

2

贪心hack数据 

6 16
9
5
5
5
4
3

Code

n, w = map(int, input().split())
N = n + 10
cat = []
car = [0] * N
ans = n
for i in range(n):
    cat.append(int(input()))
cat.sort(reverse=True)
# 优化,先装胖猫搜索分支少

def dfs(pm, pc):
    # pm,当前选定的猫, 0~n-1 
    # pc,当前车的数量, 1~n  ,注意参数的意义
    global ans, w
    if pc > ans:
        # 超过最大答案return
        return
    if pm == n:
        # 装完了猫,判断答案
        ans = min(ans, pc)
        return

    # 之前的车若有空间能装上这个猫
    # 车的数量保持不变,搜索下一个猫
    for i in range(pc):
        if car[i] + cat[pm] <= w:
            car[i] += cat[pm]
            dfs(pm + 1, pc)
            car[i] -= cat[pm]
            # 恢复
    # 不放在之前的车上,新开车来放这个猫
    car[pc] = cat[pm]
    dfs(pm + 1, pc + 1)
    car[pc] = 0


dfs(0, 0)
print(ans)

夺宝游戏  前缀和、树状数组、离散化

题目描述

小H在玩一个游戏,游戏的规则是这样的:有一块3*n个格子组成的区域,即有3行n列,每一块格子上都有一个价值为v的宝物,游戏开始前小H在这块区域的起点:左上角(1,1)处,他需要要走到这块区域的终点:右下角(3,n)处。

他每次只能向右或者向下移动一格,不能向左或者向上移动。每走过一块格子就会将这块格子的宝物收入囊中(小H出生在(1,1)处,所以(1,1)处的宝物可以直接获得),到达终点后,小H拥有的宝物价值必须大于等于K,才能赢得游戏。请问小H有多少种走法能最终赢得游戏。

输入格式:

第一行两个正整数n, k。0 <= k <= 1e10。

接下来三行,每行n个整数,第i行第j个整数vij表示该块格子宝物的价值。0<=v<=1e4。

输出格式:

小H赢得游戏的不同方法数。

输入样例:

在这里给出一组输入。例如:

3 10
1 1 1
2 2 2
3 3 3

输出样例:

在这里给出相应的输出。例如:

4

3/22 初步想法,如此dp,貌似数据范围有点难受

这样做和暴搜一样,只能过一个,吐了

NEWIDEA!倒过来搜试试,先dp一个最大价值max,再从[k,max]-ma[3][n]  搜索判断

依旧不行,但是找到正解了,链接的最后一题

软件学院蓝桥杯选拔赛_马上就要英语考试了,小t决定在接下来n天内好好背背单词,为此小t列了一个详细的计-CSDN博客

我们需要注意他只有三行

暴力的写法就是枚举第一行向下走的点和第二行向下走的点

对暴力的公式进行变形,按i,j移到两侧,发现是求正序对,考虑二进制索引树

树状数组(求逆序对)_树状数组求逆序对-CSDN博客

太恶心了,py好像过不了这个题,我吐了

3.24 py最后三个点还是超时,恶心

Code

N = int(1e6 + 10)
bit = [0] * (N * 4)
n, k = map(int, input().split())
q = [[0] * N for i in range(4)]
ss = [[0] * N for i in range(4)]

for i in range(1, 4):
    tmp = list(map(int, input().split()))
    for j in range(1, n + 1):
        q[i][j] = tmp[j - 1]
        ss[i][j] = ss[i][j - 1] + q[i][j]

alls = []
left = [0] * N
for i in range(1, n + 1):
    tmp = ss[2][i] - ss[3][i - 1]
    left[i] = tmp
    alls.append(tmp)
alls = list(set(alls))
alls = sorted(alls)


def lowbit(x):
    return x & -x


def add(p, x):
    while p <= n:
        bit[p] += x
        p += lowbit(p)


def fd(p):
    res = 0
    while p:
        res += bit[p]
        p -= lowbit(p)
    return res


def rang(l, r):
    return fd(r) - fd(l - 1)


def bifd(x):
    l, r = 0, len(alls)
    while l < r:
        mid = (l + r) // 2
        if alls[mid] >= x:
            r = mid
        else:
            l = mid + 1
    return r + 1


for i in range(1, n + 1):
    add(bifd(left[i]), 1)
ans = 0
for i in range(1, n + 1):
    tmp = k - ss[1][i] - ss[3][n] + ss[2][i - 1]
    ans += rang(bifd(tmp), n)
    add(bifd(left[i]), -1)
# 对于单个数组如[1,5,3,8,999] 求正序对
# 边把数字离散化的顺序加入bit边求累计和
# 但是现在是不等式 left<=tmp
# left已经全部add到bit中了
# 枚举tmp,查看tmp在排好序(小到大)的left中的位置(第一个大于等于)
# 按照这个位置去做累计和
# 然后在bit中对left的这个位置做add(-1),这个点我们已经用了
# 对于二叉索引树的理解依然很肤浅
print(ans)

寻宝路线 dp,搜索

在一个m行n列方格矩阵中,每一个方格内摆放着价值不等的宝贝(价值可正可负),让小明感到好奇的是,从左上角到达右下角的所有可能路线中,能捡到宝贝的价值总和最大是多少?而且这种达到最大值的路线
又有多少条?【注意:只能从一个格子向下或向右走到相邻格子,并且走到的格子宝贝一定会被捡起。】

输入格式:

第一行为整数m,n(均不大于100),下一行开始会有一个m行n列的整数方阵,对应方格矩阵中的宝贝价值(这些值的绝对值都不超过500)。

输出格式:

单独一行输出2个整数,分别为能捡到宝贝价值总和的最大值和达到最大值的路线数量,2个整数间隔一个空格。

输入样例:

在这里给出一组输入。例如:

4  5
2  -1  6  -2  9
-3  2  5  -5  1
5   8  3  -2  4
5   2  8  -4  7

输出样例:

对应的输出为:

26 3

dp每一步的最优,dfs或bfs时根据是否最优判断是否继续递归

这个破题内存限制1MB,python java过不了

Code

n, m = map(int, input().split())
li = [[0] * (m + 1)]
li += [[0] + list(map(int, input().split())) for _ in range(n)]
dp = [[0] * (m + 1) for i in range(n + 1)]
for i in range(1, m + 1):
    dp[1][i] = dp[1][i - 1] + li[1][i]
for i in range(1, n + 1):
    dp[i][1] = dp[i - 1][1] + li[i][1]
for i in range(2, n + 1):
    for j in range(2, m + 1):
        tmp = li[i][j]
        dp[i][j] = max(dp[i - 1][j] + tmp, dp[i][j - 1] + tmp)
ans, ma = 0, dp[n][m]
dx, dy = [1, 0], [0, 1]


def dfs(x, y, res):
    global ans
    res += li[x][y]
    if x == n and y == m and res == dp[n][m]:
        ans += 1
    for i in range(2):
        nx = x + dx[i]
        ny = y + dy[i]
        if nx > n or ny > m:
            continue
        if res + li[nx][ny] == dp[nx][ny]:
            dfs(nx, ny, res)


dfs(1, 1, 0)
print(dp[n][m], ans)

社交集群 并查集

当你在社交网络平台注册时,一般总是被要求填写你的个人兴趣爱好,以便找到具有相同兴趣爱好的潜在的朋友。一个“社交集群”是指部分兴趣爱好相同的人的集合。你需要找出所有的社交集群。

输入格式:

输入在第一行给出一个正整数 N(≤1000),为社交网络平台注册的所有用户的人数。于是这些人从 1 到 N 编号。随后 N 行,每行按以下格式给出一个人的兴趣爱好列表:

Ki​: hi​[1] hi​[2] ... hi​[Ki​]

其中Ki​(>0)是兴趣爱好的个数,hi​[j]是第j个兴趣爱好的编号,为区间 [1, 1000] 内的整数。

输出格式:

首先在一行中输出不同的社交集群的个数。随后第二行按非增序输出每个集群中的人数。数字间以一个空格分隔,行末不得有多余空格。

输入样例:

8
3: 2 7 10
1: 4
2: 5 3
1: 4
1: 3
1: 4
4: 6 8 1 5
1: 4

输出样例:

3
4 3 1

 Code

from collections import defaultdict

n = int(input())
f = [i for i in range(n + 1)]
ho = [0 for i in range(1010)]


def fd(x):
    if f[x] != x:
        f[x] = fd(f[x])
    return f[x]


for i in range(1, n + 1):
    li = list(input().split())
    li = li[1:]
    li = map(int, li)
    for j in li:
        if ho[j] == 0:
            ho[j] = i
        else:
            f[fd(i)] = fd(ho[j])
d = defaultdict(int)
for i in range(1, n + 1):
    d[fd(i)] += 1
q = []
for i in list(d.keys()):
    q.append(d[i])
q = sorted(q, reverse=True)
print(len(q))
print(*q)

第一个有该爱好的人作为祖宗,后来出现有该爱好的作为其后代

24,25行,遍历每个人,找他的祖宗,统计个数

城市间紧急救援 Dij

作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。

输入格式:

输入第一行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N−1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。

第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。

输出格式:

第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。

输入样例:

4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2

输出样例:

2 60
0 1 3

Code

g = [[float('inf')] * 510 for i in range(511)]
st = [0] * 510
n, m, s, d = map(int, input().split())
jyd = list(map(int, input().split()))
for i in range(m):
    a, b, c = map(int, input().split())
    g[a][b] = c
    g[b][a] = c
dis = [float('inf')] * 510
ans = [0] * 510
cnt = [0] * 510
pre = [-1] * 510
dis[s] = 0
ans[s] = jyd[s]
cnt[s] = 1
for i in range(n):
    t = -1
    j = 0
    while j < n:
        if st[j] == 0 and (t == -1 or dis[j] < dis[t]):
            t = j
        j += 1
    st[t] = 1
    for j in range(n):
        if dis[j] > dis[t] + g[t][j]:
            dis[j] = dis[t] + g[t][j]
            ans[j] = ans[t] + jyd[j]
            cnt[j] = cnt[t]
            pre[j] = t
        elif dis[j] == dis[t] + g[t][j]:
            cnt[j] += cnt[t]
            if ans[j] < ans[t] + jyd[j]:
                ans[j] = ans[t] + jyd[j]
                pre[j] = t
print(cnt[d], ans[d])
t = d
q = []

while t != -1:
    q.append(t)
    t = pre[t]

q = q[::-1]
print(*q)

 pre维护前驱初始化为-1,邻接矩阵初始化无穷大,Dij中dist初始化无穷大

Dij开始不需要把开始点的st设为1

秀恩爱分得快 

古人云:秀恩爱,分得快。

互联网上每天都有大量人发布大量照片,我们通过分析这些照片,可以分析人与人之间的亲密度。如果一张照片上出现了 K 个人,这些人两两间的亲密度就被定义为 1/K。任意两个人如果同时出现在若干张照片里,他们之间的亲密度就是所有这些同框照片对应的亲密度之和。下面给定一批照片,请你分析一对给定的情侣,看看他们分别有没有亲密度更高的异性朋友?

输入格式:

输入在第一行给出 2 个正整数:N(不超过1000,为总人数——简单起见,我们把所有人从 0 到 N-1 编号。为了区分性别,我们用编号前的负号表示女性)和 M(不超过1000,为照片总数)。随后 M 行,每行给出一张照片的信息,格式如下:

K P[1] ... P[K]

其中 K(≤ 500)是该照片中出现的人数,P[1] ~ P[K] 就是这些人的编号。最后一行给出一对异性情侣的编号 A 和 B。同行数字以空格分隔。题目保证每个人只有一个性别,并且不会在同一张照片里出现多次。

输出格式:

首先输出 A PA,其中 PA 是与 A 最亲密的异性。如果 PA 不唯一,则按他们编号的绝对值递增输出;然后类似地输出 B PB。但如果 A 和 B 正是彼此亲密度最高的一对,则只输出他们的编号,无论是否还有其他人并列。

输入样例 1:

10 4
4 -1 2 -3 4
4 2 -3 -5 -6
3 2 4 -5
3 -6 0 2
-3 2

输出样例 1:

-3 2
2 -5
2 -6

输入样例 2:

4 4
4 -1 2 -3 0
2 0 -3
2 2 -3
2 -1 2 
-3 2

输出样例 2:

-3 2

Hint 1

 注意 ' -0' 的出现,所以输入数据不能鲁莽的转为int

Code

from collections import defaultdict

n, m = map(int, input().split())
ke = []
de = defaultdict(list)
for i in range(m):
    tmp = list(input().split())
    ke.append(int(tmp[0]))
    tmp = tmp[1:]
    de[i] = tmp
a, b = input().split()

nv = defaultdict(int)
nan = defaultdict(int)


def search(x):
    if x[0] == '-':
        for i in range(m):
            if x in de[i]:
                w = 1 / ke[i]
                for j in de[i]:
                    if j[0] != '-':
                        nv[j] += w
    else:
        for i in range(m):
            if x in de[i]:
                w = 1 / ke[i]
                for j in de[i]:
                    if j[0] == '-':
                        nan[j] += w


search(a)
search(b)
f = 1
qa, qb = [], []
if a[0] == '-':
    ma = nv[b]
    mb = nan[a]
    for i in nv:
        if nv[i] > ma:
            f = 0
            qa.clear()
            ma = nv[i]
            qa.append(i)
        elif nv[i] == ma:
            qa.append(i)
    for i in nan:
        if nan[i] > mb:
            f = 0
            qb.clear()
            mb = nan[i]
            qb.append(i)
        elif nan[i] == mb:
            qb.append(i)
else:
    ma = nan[a]
    mb = nv[b]
    for i in nv:
        if nv[i] > mb:
            f = 0
            qb.clear()
            mb = nv[i]
            qb.append(i)
        elif nv[i] == mb:
            qb.append(i)
    for i in nan:
        if nan[i] > ma:
            f = 0
            qa.clear()
            ma = nan[i]
            qa.append(i)
        elif nan[i] == ma:
            qa.append(i)

if f:
    print(a, b)
else:
    qa = sorted(qa, key=lambda x: abs(int(x)))
    qb = sorted(qb, key=lambda x: abs(int(x)))
    for i in qa:
        print(a, i)
    for i in qb:
        print(b, i)

这个模拟写的很屎,有时间后把函数封装一下,让屎变成雅屎

天梯赛补题笔记到此为止,接下来专心备战LQB了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值