A 人人有份(623/5512)
题目描述
问题分析
-
问题背景:
- 学生可以选择参加竞赛类比赛或社科类比赛。
- 竞赛类比赛的奖项有一等奖、二等奖、三等奖,共3种。
- 社科类比赛的奖项有特等奖、一等奖、二等奖、三等奖、优秀奖,共5种。
- 需要设计比赛的数量,使得每个学生在参加的所有比赛中都能获奖,且所有学生的获奖情况各不相同。
-
数学模型:
- 假设举办 i 场竞赛类比赛,每场比赛有3种奖项,那么一个学生参加竞赛类比赛的获奖情况有
种。
- 假设举办 j 场社科类比赛,每场比赛有5种奖项,那么一个学生参加社科类比赛的获奖情况有
种。
- 总的获奖情况数为
。
- 需要找到是否存在正整数 i 和 j,使得
。
- 假设举办 i 场竞赛类比赛,每场比赛有3种奖项,那么一个学生参加竞赛类比赛的获奖情况有
解题思路
-
确定范围:
- i 和 j 的范围可以通过对数来确定。因为
和
都必须小于等于n,所以i 的最大值为 ⌊log3(n)⌋+1,j的最大值为 ⌊log5(n)⌋+1。
- i 和 j 的范围可以通过对数来确定。因为
-
枚举法:
- 枚举所有可能的 i 和 j,检查是否存在
。
- 枚举所有可能的 i 和 j,检查是否存在
代码实现(python)
import math
def fun(n):
for i in range(1, int(math.log(n, 3))+2):
for j in range(1, int(math.log(n, 5))+2):
if pow(3, i) + pow(5, j) == n:
return "Yes"
return "No"
for _ in range(int(input())):
print(fun(int(input())))
B 齐响诗班(167/1397)
题目描述
问题分析
-
问题背景:
- 有 n 个同学,每个同学的歌声有一个优美度 ai。
- 你需要选择一个风格 x(1 到 k),使得所有两两合唱的优美度之和最大化。
- 优美度的计算公式为:
。
- 最终的评分是对 998244353 取模的结果。
-
目标:
- 选择一个风格 x,使得所有两两合唱的优美度之和最大化,并且在多个风格评分相等的情况下,选择最小的风格 x。
解题思路
-
计算两两合唱的优美度:
- 对于每个风格 x,我们需要计算所有两两合唱的优美度之和。
- 两两合唱的优美度之和可以表示为:
- 这个公式可以进一步简化为:
- 进一步化简为:
-
计算总优美度:
- 计算所有 ai 的总和 S。
- 对于每个风格 x,计算总优美度
。
- 由于最终的评分是对 998244353 取模的结果,所以在计算过程中需要取模。
-
选择最佳风格:
- 遍历所有风格 x,计算每个风格的总优美度,并记录最大值和对应的风格。
- 如果多个风格的评分相等,选择最小的风格。
C 黑客攻击(13/509)
题目描述
问题分析
-
问题背景:
- 比赛由 n 个电脑节点组成,任意两台电脑之间都有专线连接,一共有
条专线。
- 1 号电脑节点和 n 号电脑节点是重要的数据节点。
- 小鱼和小猫轮流行动,每个回合可以选择一条专线进行入侵,切断专线连接的两台电脑之间的连接。
- 如果在某个回合后,从 1 号电脑节点到 n 号电脑节点的路径被完全切断,那么这个人就输了。
- 主办方在比赛开始前已经切断了 m 条专线,然后由小鱼开始操作。
- 比赛由 n 个电脑节点组成,任意两台电脑之间都有专线连接,一共有
-
目标:
- 判断最终谁会获胜。
解题思路
-
图的连通性:
- 由于任意两台电脑之间都有专线连接,初始情况下图是完全图。
- 主办方提前切断了 m 条专线,我们需要判断这些切断的专线是否会影响 1 号节点到 n 号节点的连通性。
-
连通性的判断:
- 使用并查集(Union-Find)来维护节点的连通性。
- 初始化并查集,将所有节点初始化为独立的集合。
- 处理提前切断的专线,将这些专线对应的节点进行合并。
- 检查 1 号节点和 n 号节点是否在同一个集合中,如果不在同一个集合中,说明已经断开,小鱼获胜。
- 如果在同一个集合中,需要进一步判断后续的操作。
-
博弈论:
- 由于小鱼和小猫都足够聪明,他们会尽量让对方处于不利的局面。
- 如果 1 号节点和 n 号节点在同一个集合中,那么需要考虑后续的切割操作。
- 如果剩余的边数为奇数,小鱼会先手操作,最终会导致小猫输掉比赛。
- 如果剩余的边数为偶数,小猫会后手操作,最终会导致小鱼输掉比赛。
D 爱鲲(229/2026)
题目描述
问题分析
-
问题背景:
- 小鱼想要报名 n 个训练班,每个训练班可以重复参加,使得最终的练习时长达到 k 年。
- 第 1 个班的练习时长是 1 年,第 2 个班的练习时长是 0.5 年,第 3 个班的练习时长是 0.25 年,以此类推。
- 需要计算有多少种不同的报名方案,使得总练习时长为 k 年。
-
数学模型:
- 第 i 个班的练习时长为 2−i+1 年。
- 设 xi 表示第 i 个班的报名次数,那么问题可以转化为求解以下方程的非负整数解的个数:
- 由于 kk 是整数,可以将方程两边乘以 2n−1,转换为:
-
动态规划:
- 定义 dp[i][j] 表示前 i 个班的练习时长总和为 j 的方案数。
- 初始状态:dp[0][0]=1,表示没有班的练习时长为 0 的方案数为 1。
- 状态转移方程:
解题思路
-
初始化:
- 初始化一个二维数组 dp,大小为
。
- dp[0][0]=1。
- 初始化一个二维数组 dp,大小为
-
动态规划:
- 遍历每个班 i(从 1 到 n)。
- 对于每个班 i,遍历所有可能的练习时长 j(从 0 到
)。
- 更新 dp[i][j] 的值,使用状态转移方程。
-
结果:
- 最终结果为 dp[n][k⋅2n−1]。
E 改题难(711/5390)
题目描述
问题分析
-
问题背景:
- 小鱼有一个难度为 a 的搜索题,他想把它改成一个难度为 b 的 DP 题。
- 可以进行以下操作:
- 花费 x 的精力把一个 i 难度的搜索题改编成同等难度的 DP 题,或降低难度改成 i−1 难度的 DP 题。
- 花费x 的精力把一个 i 难度的 DP 题改编成同等难度的搜索题,或增加难度改成 i+1难度的搜索题。
- 花费 k×y的精力,将一个题目的难度上调或者下降 k(不论是搜索题还是 DP 题)。
- 题目难度范围为 1 到 100。
-
目标:
- 找到最小的精力花费,使搜索题变成指定难度的 DP 题。
解题思路
-
基本情况:
- 如果 a=b,只需要花费一次 x 的精力将搜索题直接改编成同等难度的 DP 题。
-
难度调整:
- 如果 a<b,有两种策略:
- 直接将搜索题改编成同等难度的 DP 题,再逐步增加难度到 b。
- 先将搜索题改编成同等难度的 DP 题,再一次性调整难度到 b。
- 如果 a>b,也有两种策略:
- 直接将搜索题改编成同等难度的 DP 题,再逐步减少难度到 b。
- 先将搜索题改编成同等难度的 DP 题,再一次性调整难度到 b。
- 如果 a<b,有两种策略:
-
计算最小精力:
- 对于每种策略,计算所需的精力,并取最小值。
代码实现(C++)
#include<iostream>
using namespace std;
int main() {
int a, b, x, y,t=0;
cin >> a >> b >> x >> y;
if (a < b)
t = min((2 * (b-a) + 1) * x, x + (b-a) * y);
else if (a == b)
t = x;
else
t = min((2 * (a - b) - 1) * x, x + (a - b-1) * y);
cout << t << endl;
return 0;
}
F 借钱难(711/3740)
题目描述
问题分析
-
问题背景:
- 小鱼的人际关系网中有 n 个人,每个人手上初始有 ai 元,希望最后手上恰好有 bi 元。
- 他们之间有 m 对关系密切的朋友,可以互相借钱。
- 需要判断是否可以通过互相借钱满足每个人的财务需求。
-
目标:
- 判断所有的人是否可以通过互相借钱满足他们的需求。
解题思路
-
总需求平衡:
- 首先,所有人的初始金额之和必须等于所有人希望的最终金额之和。如果不相等,显然是不可能满足需求的。
- 即:
。
-
连通性:
- 由于只有关系密切的朋友之间可以互相借钱,我们需要检查每个人是否可以通过这些关系互相借钱。
- 使用并查集(Union-Find)来维护这些关系,确保每个连通分量内的初始金额之和等于最终金额之和。
-
连通分量检查:
- 对于每个连通分量,检查该分量内所有人的初始金额之和是否等于最终金额之和。
- 如果任何一个连通分量不满足这个条件,那么无法满足所有人的需求。
G 出题难(94/579)
题目描述
问题分析
-
问题背景:
- 小鱼有一个原始题目,包含两个模块:一个 trick (T) 和一个 idea (I),即 "TI"。
- 小鱼可以通过以下四种操作之一来扩展题目:
- 将相邻的两个模块 TT 变成 TAT,其中 A 为 T 或 I 中的一个。
- 将相邻的两个模块 TI 变成 TBI,其中 B 为 T 或 I 中的一个。
- 将相邻的两个模块 IT 变成 ICT,其中 C 为 T 或 I 中的一个。
- 将相邻的两个模块 II 变成 IDI,其中 D 为 T 或 I 中的一个。
- 需要计算当题目中正好包含 n 个模块时,有多少种题目的可能。
-
目标:
- 计算当题目中正好包含 n 个模块时,可能的题目的数量,并对
取模。
- 计算当题目中正好包含 n 个模块时,可能的题目的数量,并对
解题思路
-
动态规划:
- 定义 dp[i][j] 表示长度为 i 的题目,最后一个模块为 j(其中 j 为 0 表示 T,1 表示 I)的方案数。
- 初始状态:dp[2][0]=1(表示 "TI"),dp[2][1]=0(因为 "IT" 不是初始状态)。
-
状态转移:
- 根据四种操作,更新 dp 数组:
- dp[i][0] 可以从 dp[i−1][0] 和 dp[i−1][1] 转移过来。
- dp[i][1] 可以从 dp[i−1][0] 和 dp[i−1][1] 转移过来。
- 具体转移方程:
- dp[i][0]=dp[i−1][0]×(A 为 T 的情况)+dp[i−1][1]×(B 为 T 的情况)
- dp[i][1]=dp[i−1][0]×(C 为 I 的情况)+dp[i−1][1]×(D 为 I 的情况)
- 根据四种操作,更新 dp 数组:
-
结果:
- 最终结果为 dp[n][0]+dp[n][1]。
H 旅行难(0/310)
题目描述
问题分析
-
问题背景:
- 小鱼有 n 个想去的城市,城市之间有 m 个旅游团。
- 每个旅游团往返于城市 xi 和城市 yi 之间,需要小鱼在 xi 和 yi 两个城市中选择一个城市找恰好 pi 个朋友来转发朋友圈。
- 小鱼在每个城市购买了 fi 个机器人号,这些机器人号会自动转发小鱼的朋友圈。
- 如果小鱼在 x 城市和 y 城市购买了相同数量的机器人账号,就不能报名参加从 x 到 y 的旅游团。
- 需要判断是否存在一种方法,使得小鱼可以从 1 号城市出发,去到任意一个城市。
-
目标:
- 判断是否存在一种方法,使得小鱼可以从 1 号城市出发,去到任意一个城市。
- 如果存在,输出每个城市购买的账号数量,使得编号越小的城市购买账号尽可能少。
解题思路
-
图的连通性:
- 由于 m 个旅游团可以连通 n 个城市,可以将城市和旅游团的关系建模为一个图。
- 图的连通性保证了从 1 号城市可以到达任意一个城市。
-
约束条件:
- 每个旅游团的要求 pi 必须在一个城市中满足。
- 不能在两个城市中购买相同数量的机器人账号。
-
贪心算法:
- 从 1 号城市开始,依次为每个城市分配机器人账号。
- 优先使得编号越小的城市购买账号尽可能少。
- 使用一个数组
f
来记录每个城市购买的账号数量。 - 遍历每个旅游团,根据旅游团的要求 pi,选择一个城市购买 pi 个账号,确保两个城市购买的账号数量不同。
-
可行性检查:
- 在分配账号的过程中,检查是否可以满足所有旅游团的要求。
- 如果存在冲突(即两个城市购买了相同数量的账号),则无法满足要求,输出 "No"。
I 联合权值(510/4459)
题目描述
问题分析
-
问题背景:
- 给定一个长度为 n 的序列 a,每个元素 ai 的范围是 1≤ai≤2000。
- 需要找到两个下标 i 和 j,使得 gcd(ai,aj)=1,并且 i+j 的值最大。
- 如果不存在这样的 i 和 j,输出 -1。
-
目标:
- 求 i+j 的最大值,其中 i 和 j 满足 gcd(ai,aj)=1。
解题思路
-
预处理:
- 由于 ai 的范围是 1 到 2000,可以预先计算每个数的所有因数。
- 使用埃拉托色尼筛法(Sieve of Eratosthenes)来预处理每个数的因数。
-
互质判断:
- 两个数互质的条件是它们的最大公约数为 1。
- 可以通过因数来判断两个数是否互质。如果两个数的因数集合没有交集,则这两个数互质。
-
双指针/二分查找:
- 为了高效地找到满足条件的 i 和 j,可以使用双指针或二分查找。
- 从最大的 i 开始,逐步减小 i,同时查找满足条件的 j。
-
优化:
- 由于 n 的最大值为
,直接两两比较会超时。因此,需要优化查找过程。
- 可以使用哈希表或数组来记录每个数的出现位置,从而快速查找满足条件的 j。
- 由于 n 的最大值为
J 螺旋塔(1346/3085)
题目描述
问题分析
-
问题背景:
- 给定一个字符串 s 和一个整数 n。
- 需要按照特定的规则构建并输出一个螺旋塔形状的字符串序列。
- 第一层是原始给定的字符串。
- 从第二层开始,每一层都是将上一层字符串的第一个字符移到末尾而形成的新字符串。
-
构建规则:
- 第一层为原始字符串 s。
- 第二层,将第一层的第一个字符移到末尾,得到新字符串。
- 第三层,将第二层的第一个字符移到末尾,得到新字符串。
- 依次类推,直到构建到第 n 层。
解题思路
-
读取输入:
- 读取字符串 s。
- 读取整数 n,表示螺旋塔的层数。
-
构建螺旋塔:
- 使用一个循环,从第 1 层到第 n 层,逐层构建字符串。
- 在每一层中,将当前字符串的第一个字符移到末尾,形成新的字符串。
-
输出结果:
每构建一层,输出该层的字符串。
代码实现(python)
s=input()
for _ in range(int(input())):
print(s)
s=s[1:]+s[0]