2023年福建农林大学程序设计校赛个人题解(无D解析)
A-这是一道原题
问题解析
从绿色材料合成到金色材料。
用 w h i l e while while 循环判断材料数是否能合成,能就合,合成后下一级材料数增加,原料数加上合成出的材料数。
AC代码
#include
using namespace std;
#include
#include
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
B-健康阳光,积极向上!
问题解析
想不到什么很好做法,直接暴力了。
根据贪心来说,要想结果越小,删掉的质因数就要越大。
对所有数进行质因数分解并记录下来,最后对所有质因数从大到小排序,把最前面 k k k个质数当作我们要删除的质因子。
然后我们把剩下的质因子全部乘起来就行。
分解因数的复杂度在 O ( log 2 a i ) O(\log_{2}{a_i}) O(log2ai) 到 O ( n ) O(\sqrt n) O(n ) 之间 。
AC代码
#include
using namespace std;
#include
#include
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
C-字一色大四喜四杠子四暗刻单骑役满确定!
问题解析
遍历字符串看有没有 7 z 7z 7z 就行。
AC代码
#include
using namespace std;
#include
#include
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
D-荣!断幺九,一番,1000点!
问题解析
说实话,这题我没想懂,不咋打雀不知道是不是只要胡牌且没有幺九牌就是段幺九。而且也不知道给的牌型是不是已经胡了让判断胡的排序。不太懂,如果有出题人能帮我解个惑就好了。
(代码学的一个大佬写的,感觉懂了点什么又好像没懂)
AC代码
#include
using namespace std;
#include
#include
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
E-可爱即是正义!
问题解析
区间前缀和模板,枚举所有 r r r 行 c c c 列的子矩阵然后用矩阵前缀和快速算结果,维护最大值就行。
注意数据可能使得最大的矩阵和为负数,维护最大值的变量初始值要够小。
AC代码
#include
using namespace std;
#include
#include
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
F-炉石传说这个游戏是没有(任何BUG)的!
问题解析
基础的计数 d p dp dp 。
设状态转移数组 f f f , f [ i ] f[i] f[i] 表示前 i i i 个字符的分割方式有 f [ i ] f[i] f[i] 种。
状态转移:如果一个长为 l e n len len 的字符串 s i si si 能匹配字符串 s t r str str 上 j j j 到 j − l e n + 1 j-len+1 j−len+1 的这一段,则有 f [ j + l e n − 1 ] = f [ j + l e n − 1 ] + f [ j − 1 ] f[j+len-1] = f[j+len-1] + f[j-1] f[j+len−1]=f[j+len−1]+f[j−1] 。
思路不难,主要是匹配字符串的方法。
遍历字符串 s t r str str ,枚举每个位置 j j j ,判断以当前字符为起点是否有字符串 s i si si 能和它匹配。
这里可以用字符串哈希快速匹配,预处理 s t r str str 的哈希数组复杂度为: O ( l e n g t h ( s t r ) ) O(length(str)) O(length(str)) ,预处理 n n n 个字符串 s s s 的哈希值的复杂度为: O ( ∑ i = 0 n l e n g t h ( s i ) ) O(\sum_{i=0}^nlength(s_i)) O(∑i=0nlength(si)) 。
每次匹配字符串复杂度为: O ( 1 ) O(1) O(1) 。
总复杂度: O ( ∑ i = 0 n l e n g t h ( s i ) ∗ l e n g t h ( s t r ) ) O(\sum_{i=0}^n length(s_i) * length(str)) O(∑i=0nlength(si)∗length(str))
AC代码
#include
using namespace std;
#include
#include
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
G-蒸蒸日上!
问题解析
出题人看来非常喜欢三国杀这款游戏呀,那我去给三国杀刷个好评罢。(逃)
根据给的字符串输出对应的外号就行。
AC代码
#include
using namespace std;
#include
#include
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
H-圆皱率_
问题解析
这题面真是给我笑死,不过我觉得题意不是很清楚,一开始都不理解要干啥,最好优化一下或者给样例加个解释罢。
(话说我这种又玩原又玩粥又玩农的算啥皮)
这题是想让你从里面选择一个子序列,使得子序列的和最大,但是不能让 a a aa aa 和 A A AA AA 挨着。
我们先把豌豆的三种基因状态 A A 、 A a 、 a a AA、Aa、aa AA、Aa、aa 分别设为 1 、 2 、 3 1、2、3 1、2、3 。
动态规划。
设二维状态转移数组 f f f , f [ i ] [ j ] f[i] [j] f[i][j] 表示在前 i i i 个豌豆中取,且最后一个豌豆状态为 j j j 的最大价值为 f [ i ] [ j ] f[i] [j] f[i][j] , j = 0 j = 0 j=0 表示一个豌豆都没取。
状态转移:
- 每次都有: f [ i ] [ j ] = f [ i − 1 ] [ j ] f[i] [j] = f[i-1] [j] f[i][j]=f[i−1][j] 。
- 如果当前的豌豆状态为 1 1 1 ,则 f [ i ] [ 1 ] = m a x ( f [ i ] [ 1 ] , f [ i ] [ j ] + a i ) ( j = 0 , 1 , 2 ) f[i] [1] = max(f[i] [1],f[i] [j] + a_i) (j = 0,1,2) f[i][1]=max(f[i][1],f[i][j]+ai)(j=0,1,2)。
- 如果当前的豌豆状态为 2 2 2 ,则 f [ i ] [ 2 ] = m a x ( f [ i ] [ 1 ] , f [ i ] [ j ] + a i ) ( j = 0 , 1 , 2 , 3 ) f[i] [2] = max(f[i] [1],f[i] [j] + a_i) (j = 0,1,2,3) f[i][2]=max(f[i][1],f[i][j]+ai)(j=0,1,2,3)。
- 如果当前的豌豆状态为 3 3 3 ,则 f [ i ] [ 3 ] = m a x ( f [ i ] [ 1 ] , f [ i ] [ j ] + a i ) ( j = 0 , 2 , 3 ) f[i] [3] = max(f[i] [1],f[i] [j] + a_i) (j = 0,2,3) f[i][3]=max(f[i][1],f[i][j]+ai)(j=0,2,3)。
最后答案为: m a x ( f [ n ] [ j ] ) ( j = 0 , 1 , 2 , 3 ) max(f[n] [j]) (j=0,1,2,3) max(f[n][j])(j=0,1,2,3) 。
AC代码
#include
using namespace std;
#include
#include
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
I-你说得对,但是……_
问题解析
但是原神是一款…………
首先我们要知道, 1 1 1 并不是一个质数,然后我们再知道,对于相邻的两个数,它们的最大公约数是 1 1 1 。
那么我们可以先按照 a [ i ] = i a[i] = i a[i]=i 的方式来排列,然后依次判断 g c d ( a [ i ] , i ) gcd(a[i],i) gcd(a[i],i) 是否为质数,如果为质数,我们就可以把它和下一位数: a [ i + 1 ] a[i+1] a[i+1] 进行交换,这样可以保证 a [ i ] a[i] a[i] 和 a [ i + 1 ] a[i+1] a[i+1] 和他们对应位置数的最大公约数都是 1 1 1 。
由于这一步会使得我们的字典序变大,所以如果 g c d ( a [ i ] , i ) gcd(a[i],i) gcd(a[i],i) 不为质数,我们就不用交换了。
特别的,如果 g c d ( a [ n ] , n ) gcd(a[n],n) gcd(a[n],n) 为质数,因为已经没有下一位了,所以我们只能和上一位,即: a [ n − 1 ] a[n-1] a[n−1] 进行交换。
这里判断质数我用的是 M i l l e r − R a b i n Miller-Rabin Miller−Rabin 素性测试,不认识的大家可以学习一下。用试除法应该也是可以过的。
AC代码
#include
using namespace std;
#include
#include
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
J-蓝色妖精小姐的树
问题解析
从数据的方式和表情包来看,都告诉了我们这题用的是珂朵莉树。
珂朵莉树是一个神奇的算法,专门负责处理这类区间修改(区间赋值)和区间询问问题,做法很暴力,所以一般只适用于随机数据,对于出题人自己造的数据,是可以把珂朵莉树给卡到超时的。
具体的大伙可以去看看珂朵莉树的由来。
至于树的问题,我们可以通过 d f s dfs dfs 序来确定每一个子树的根 u u u 负责的是哪个区间,修改这一整个子树,就相当于修改这个区间。
AC代码
#include
using namespace std;
#include
#include
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include