本次比赛的出题表如下:
退役一年,勋总还是那么强呜呜呜
出题人:陈文静
计算 (homo)10=(114)5+(141)9+(198)10(homo)_{10}=(114)_5+(141)_9+(198)_{10}(homo)10=(114)5+(141)9+(198)10 ,其中 (x)y(x)_y(x)y 代表数字 xxx 是用 yyy 进制表示的。
按权展开计算十进制结果,并求和。
(114)5=(1×52+1×51+4×50)10=(34)10(114)_5=(1\times5^2+1\times5^1+4\times5^0)_{10}=(34)_{10}(114)5=(1×52+1×51+4×50)10=(34)10
(141)9=(1×92+4×91+1×90)10=(118)10(141)_9 = (1\times9^2+4\times9^1+1\times9^0)_{10}=(118)_{10}(141)9=(1×92+4×91+1×90)10=(118)10
(homo)10=(34)10+(118)10+(198)10=(350)10(homo)_{10}=(34)_{10}+(118)_{10}+(198)_{10}=(350)_{10}(homo)10=(34)10+(118)10+(198)10=(350)10
因此 homohomohomo 是 350350350
第十三届蓝桥杯C/C++省赛B组 E题
进制规定了数字在数位上逢几进一。
XXX 进制是一种很神奇的进制,因为其每一数位的进制并不固定!例如说某种 XXX 进制数,最低数位为二进制,第二数位为十进制,第三数位为八进制,则X 进制数 321321321 转换为十进制数为 656565。
现在有两个 XXX 进制表示的整数 AAA 和 BBB,但是其具体每一数位的进制还不确定,只知道 AAA 和 BBB 是同一进制规则,且每一数位最高为 NNN 进制,最低为二进制。请你算出 A−BA − BA−B 的结果最小可能是多少。
请注意,你需要保证 AAA 和 BBB 在 XXX 进制下都是合法的,即每一数位上的数字要小于其进制。
输出一行一个整数,表示 XXX 进制数 A−BA − BA−B 的结果的最小可能值转换为十进制后再模 100000000710000000071000000007 的结果。
实际上进位计数制,更重要的是计数。我们可以根据进位的规则,从 000 开始不断加 111 ,根据进位规则产生新的数字。最后我们既可以通过进位表示得出某个数字表示的大小,也可以通过某个数字的大小得到进位表示。
XiX_iXi | X0X_0X0 | X1X_1X1 | X2X_2X2 | X3X_3X3 | X4X_4X4 | X5X_5X5 | X6X_6X6 | X7X_7X7 | X8X_8X8 |
---|---|---|---|---|---|---|---|---|---|
Base10Base_{10}Base10 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
Base2Base_2Base2 | 0 | 1 | 10 | 11 | 100 | 101 | 110 | 111 | 1000 |
Base5Base_5Base5 | 0 | 1 | 2 | 3 | 4 | 10 | 11 | 12 | 13 |
现在给定一个数字 XXX ,只要知道 XXX 之前有多少个数字就可以确定 XXX 的大小。
举一个十六进制的例子:(ABC)16=(A00+B0+C)16(ABC)_{16}=(A00+B0+C)_{16}(ABC)16=(A00+B0+C)16 ,假设我们现在想知道 (ABC)16(ABC)_{16}(ABC)16 在五进制下表示是什么,我们可以考虑 (A00)16,(B0)16,(C)16(A00)_{16} ,(B0)_{16},(C)_{16}(A00)16,(B0)16,(C)16 分别在五进制下的表示是什么,最后将这三者用五进制加法加起来即可。
对于 (A00)16(A00)_{16}(A00)16 ,我们可以固定最高位为 [(0)16,(9)16][(0)_{16},(9)_{16}][(0)16,(9)16] 这个范围的数,那么低两位任意取 [(0)16,(F)16][(0)_{16},(F)_{16}][(0)16,(F)16] 中的任意值组合一定都小于 (A00)16(A00)_{16}(A00)16,根据计数乘法原理可以知道低两位存在 (F+1)16×(F+1)16(F+1)_{16} \times (F+1)_{16}(F+1)16×(F+1)16 种组合可能,最后再乘上最高位可能取值的数量。 (A00)16(A00)_{16}(A00)16 用十六进制乘法表示就是 (9+1)16×(F+1)16×(F+1)16(9+1)_{16} \times (F+1)_{16} \times (F+1)_{16}(9+1)16×(F+1)16×(F+1)16 ,于是可以将乘法的十六进制数转换为五进制数进行乘法就得到了 (A00)16(A00)_{16}(A00)16 在五进制下的表示,即 (14+1)5×(30+1)5×(30+1)5(14+1)_5 \times (30+1)_5 \times (30+1)_5(14+1)5×(30+1)5×(30+1)5 。
最终可以得到
(ABC)16=(A00)16+(B0)16+(C)16=(9+1)16×(F+1)16×(F+1)16+(A+1)16×(F+1)16+(C)16=(14+1)5×(30+1)5×(30+1)5+(20+1)5×(30+1)5+(22)5\begin{aligned} (ABC)_{16} &= (A00)_{16}+(B0)_{16}+(C)_{16} \\ &= (9+1)_{16}\times (F+1)_{16} \times (F+1)_{16} + (A+1)_{16} \times (F+1)_{16} + (C)_{16} \\ &=(14+1)_5 \times (30+1)_5 \times (30+1)_5 +(20+1)_5 \times (30+1)_5 + (22)_5 \end{aligned} (ABC)16=(A00)16+(B0)16+(C)16=(9+1)16×(F+1)16×(F+1)16+(A+1)16×(F+1)16+(C)16=(14+1)5×(30+1)5×(30+1)5+(20+1)5×(30+1)5+(22)5
根据五进制加法就可以得到五进制的表示,另外乘法本质上也是加法。观察每一个数位,乘的数值始终是一致的,因此可以把这个固定值称为权,以上式子展开的过程称为按权展开。
对于蓝桥杯的这道题,可以先考虑 XXX 进制如何转换为 101010 进制,我们可以参考上面的思考过程。因为每一个数位的进位基数可能是不一样的,因此每一位的权就变为更低位进位基数的连乘积。因为 XXX 进制的每一位的进制基数是不确定的,但是我们知道位权是由更低位进制基数决定的,那么贪心的想,每一位的进位基数尽可能小就可以让数的整体尽可能小,但是基数不能小于或等于 A,BA,BA,B 对应位的最大值(这是进位制的限制)。
此外还需要考虑减法借位是否会影响贪心的策略:[1] 不产生借位,不影响贪心策略 [2] 产生借位,在确定高位进位基数的情况下,借位对高位的影响一致,而当前位进位基数越小借位后的数值越小,且进位基数越小高位的权越小。因此减法借位不会影响贪心策略。
最后生活中常见的 XXX 进制即时分秒,进位基数分别为 24,60,6024,60,6024,60,60 。
出题人:陈文静
区间 [1919,114514][1919,114514][1919,114514] 中的正整数构成数对
可以写一个复杂度为 O(n2)O(n^2)O(n2) 的程序枚举所有数对,将数字转换为字符串比较并统计答案,C++耗时大概 404040 分钟左右。
也可以考虑先对 nnn 个数字按字典序排序,时间复杂度 O(nlogn)O(n\log n)O(nlogn),那么字典序大于排序后第 iii 个数字的有 n−in-in−i 个,最后求和即可。
可以考虑:对于 nnn 个数字,一共进行 n×nn \times nn×n 次比较,其中 nnn 个数对的比较是相等的。剩下 n×n−nn \times n - nn×n−n 个数对一半是满足小于关系,一半满足大于关系,因此满足大于关系的数量为 n×n−n2\frac{n \times n - n}{2}2n×n−n ,代入公式时间复杂度 O(1)O(1)O(1)。
区间长度 n=114514−1919+1=112596n = 114514-1919+1=112596n=114514−1919+1=112596 ,因此最终答案为 112596×1125952=6338873310\frac{112596 \times 112595}{2}=63388733102112596×112595=6338873310
C++计算时需要注意类型,答案超过 int
范围。
出题人:林贝宁
使用深度优先搜索算法先写出代码,然后用代码跑出答案即可,最后答案为2279184
。因为是填空题没有时间限制要求,所以不需要状态压缩优化也可以在2
分钟内跑出来。
下面是我用JAVA
写的状态压缩版dfs
搜索的代码,语法大致同C++
,供参考
import java.util.*;public class Main {private static int n, allOne, answerNumber;// 三个变量分别表示:n个皇后问题, 一行n个位置棋盘全部赋1的状态, 解的数量public static void findAnswer(int[] chessBoard, int row, int nowState, int mainDiagonal, int deputyDiagonal) {if (row == n) //找到一组合法解{answerNumber ++ ;return;}int remainingColumn = allOne & (~ (nowState | mainDiagonal | deputyDiagonal));//剩余的还能填写的列 = n个1 - (已经填写的列+主副对角线被占用的位置)int nowPosition;// 当前需要填写的位置状态int nextState, nextMain, nextDeputy;//下一层搜索,列被占用的状态,主对角线占用状态,副对角线占用状态for (int i = 0; i < n; i++) {if (((remainingColumn >> i) & 1) == 0) //当前行第i个位置不能填continue;nowPosition = 1 << i; //第i个位置的位状态chessBoard[row] = i; //第row行,皇后放在第i列的位置上面nextState = nowState | nowPosition;//下一层搜索,列被占用的状态nextMain = (mainDiagonal | nowPosition) >> 1;//下一层搜索,主对角线占用状态nextDeputy = (deputyDiagonal | nowPosition) << 1;//下一层搜索,副对角线占用状态findAnswer(chessBoard, row + 1, nextState, nextMain, nextDeputy);//进入下一层搜索}return;}public static void main(String[] args) {Scanner readScanner = new Scanner(System.in);n = readScanner.nextInt();allOne = (int) (1L << n) - 1; int[] chessBoard = new int[n]; //chessBoard[i]表示第i行,皇后摆放在当前行第几个位置findAnswer(chessBoard, 0, 0, 0, 0);if(answerNumber == 0){System.out.println("No Solution"); //无解System.exit(0); //直接结束程序}System.out.println("There are a total of " + answerNumber + " answers"); //有多少组解}
}
出题人 :林贝宁
输出YES即可。
#include
int main()
{std::cout << "YES" << std::endl;return 0;
}
出题人:吴杰
当市场价 sis_isi 大于成本 XXX 时,累加概率。最后输出时特判。
#include
using namespace std;
const int N = 104;int p[N], s[N];int main(){int n,X;cin>>n>>X;for(int i=1;i<=n;i++) cin>>p[i];for(int i=1;i<=n;i++) cin>>s[i];int ans=0;for(int i=1;i<=n;i++){if(s[i]>X) ans+=p[i];}if(ans==0) cout<<"shu ma le"<
出题人:陈文静
给一个长度为 nnn 的一维元胞自动机和初始序列,元胞的染色情况由元胞数值的奇偶决定,问 T=tT=tT=t 时刻元胞自动机的染色情况
按题意模拟即可,直接累加会爆int
类型,但溢出不影响奇偶性。
也可以对三个数奇偶性进行讨论,若出现三个奇数相加结果仍然奇数,两个奇数一个偶数相加结果为偶数,一个奇数两个偶数相加结果为奇数,三个偶数相加结果为偶数。序列初始值为 000 或 111 ,上面的讨论相当于是异或运算,因此也可以将加法改为异或。
状态更新取决于上个状态,因此不能直接用一维数组模拟,可以使用二维数组模拟,使用滚动数组对二维数组进行空间优化。
#include
using namespace std;
int S[1001][101];
int main()
{int n, t;cin >> n >> t;for (int i = 1; i <= n; i++) cin >> S[0][i]; /*初始状态*/for (int i = 1; i <= t; i++)for (int j = 1; j <= n; j++)S[i][j] = S[i - 1][j - 1] ^ S[i - 1][j] ^ S[i - 1][j + 1]; /*异或 / 加法都可以*/for (int i = 1; i <= n; i++)cout << (S[t][i] ? "B" : "W"); /*输出最终状态染色情况*/return 0;
}
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int t = in.nextInt();int[][] S = new int[1001][101];for (int i = 1; i <= n; i++) {S[0][i] = in.nextInt();}for (int i = 1; i <= t; i++) {for (int j = 1; j <= n; j++) {S[i][j] = S[i - 1][j - 1] ^ S[i - 1][j] ^ S[i - 1][j + 1];}}for (int i = 1; i <= n; i++)System.out.print(S[t][i] == 1 ? "B" : "W");in.close();}
}
n, t = map(int, input().split())S = [[0 for i in range(0, 101)] for j in range(0, 1001)]
S[0] = [0]+list(map(int, input().split()))+[0]
for i in range(1, t+1):for j in range(1, n+1):S[i][j] = S[i-1][j-1] ^ S[i-1][j] ^ S[i-1][j+1]
for i in range(1, n+1):if S[t][i]:print("B", end='')else:print("W", end='')
出题人: 吴杰
瓶盖兑矿泉水炉石版,虽然游戏马上要寄了
因为 Z 出题人:蔡培伟 在一个 n×nn \times nn×n 的矩阵内给定 kkk 个特殊点,问所有点到特殊点的最短距离的总和是多少。 设矩阵上两个点的位置为 (x1,y1),(x2,y2)(x_1, y_1),(x_2,y_2)(x1,y1),(x2,y2) ,那么点与点之间之间的距离为 ∣x1−x2∣+∣y1−y2∣|x_1 - x_2| + |y_1 - y_2|∣x1−x2∣+∣y1−y2∣ 。 知识点:多源 BFS 。 假设我们只有一个点 vvv ,从这个点开始进行 bfs ,就像类似于从一个着火点开始,逐步蔓延至周边的其他位置,搜索到的点顺序是按照其距离源点 vvv 的距离由近到远进行排序。 在这道题中有多个源点,我们只需要将这几个点加入 bfs 的队列,直接进行 bfs ,就能得到每个点到其最近源点的距离,累加起来就是答案了。 出题人:陈文静 一天可以建造一台机器,若机器在第 xxx 天建造,第 x+1x+1x+1 天 000 点运行,并于第 x+d+1x+d+1x+d+1 天 000 点报废,建造机器时刻的取值范围为 [0,+∞)[0,+ \infin)[0,+∞)。给出 nnn 个不同的时刻,每个时刻都需要有至少 aaa 台机器同时工作,问是否存在一种方案建造机器使得对于给出的 nnn 个时刻至少都有 aaa 台机器同时工作,如果存在至少需要多少台。 第 ttt 天建造的机器只在 [t+1,t+d+1)[t+1,t+d+1)[t+1,t+d+1) 时间段工作。 对于第 tit_iti 天,我们只需要检查 [max(0,ti−d),ti−1][\max(0,t_i-d),t_i-1][max(0,ti−d),ti−1] 天建造的机器数量,如果数量不足 aaa ,可以利用贪心思想从后往前依次枚举可以建造的时刻补充机器至 aaa 台并标记补充建造的时刻(贪心:建造机器的时间尽可能靠后)。同时只需要满足 a≤da \le da≤d 且 a≤t1a \le t_1a≤t1 一定存在解,当然也可以在枚举的过程中判断是否有解。 排除无解情况以后,可以考虑第 tit_iti 天,[ti−1,ti)[t_{i-1} ,t_i)[ti−1,ti) 区间在考虑第 tit_iti 天之前不可能建造过机器,最坏情况是这个区间都建造机器才能满足第 tit_iti 天同时工作机器数量大于或等于 aaa。因此我们可以维护建造时刻的队列 qqq,队首建造时刻保持机器对 tit_iti 时刻有效,需要增加机器的数量即 max(0,a−q.size())\max(0,a-q.size())max(0,a−q.size()) ,且增加机器建造的时间为 [ti−1,ti)[t_{i-1},t_i)[ti−1,ti) 区间从后往前连续的天数(贪心)。 本题定位为简单题,没有卡掉前一种做法,只需要想到贪心思路即可通过本题,且Java和Python(pypy3)使用第一种做法也可以通过。 代码实现给出C++两种做法实现、Java和Python第二种做法的实现。 当然本题输出 出题人:周鑫 利用C++中的set直接进行模拟可以得到606060的分数。 但是为什么只有606060分? 科普一下set中“==”的逻辑: 也就是说,在最坏情况下,两个集合进行比较的时间复杂度是O(n)O(n)O(n)的。故用这个做法本题最坏的时间复杂度是O(n2)O(n^2)O(n2),不能通过此题。 回忆一下高中乃至小学学过的知识:如何判断两个数或两个式子相等? 一个显然的想法是:对两个式子做差,如果差值为000,则两个式子相等。 我们利用这个思想来解决这个问题。 显然判断一个集合是否为空集是简单的:只要判断该集合大小是否为000即可。 我们令集合SSS为 其中A,BA,BA,B为题意中所表示的两个集合 显然,若SSS是空集,那么A=BA=BA=B (A∪B)−(A∩B)=∅→(A∪B)=(A∩B)→A=B\begin{aligned} &(A \cup B) - (A \cap B) = \varnothing \\ \rightarrow &(A \cup B) = (A \cap B)\\ \rightarrow& A = B \end{aligned} →→(A∪B)−(A∩B)=∅(A∪B)=(A∩B)A=B 考虑维护这个集合SSS。 如何维护? 看下面这个例子。 现在我们需要将数xxx插入AAA中,在插入前,会有以下两种情况中的其中一种发生 对于第一种情况 我们忽略即可。 那么对于第二种情况,则也有以下两种情况的其中一种发生 由于x∉Ax \not\in Ax∈A,则如果第一种情况发生,则是x∈Bx \in Bx∈B,按照SSS的定义我们把xxx从SSS中移去;如果是第二种情况发生,则是x∉Bx \not\in Bx∈B发生,则我们将xxx插入SSS中即可。 对于每次查询,只需要判断SSS是否为空集即可。 时间复杂度为O(nlogn)O(n\log n)O(nlogn) 回忆一下我们在606060分做法中遇到的困难:set直接比较的复杂度太高,无法直接比较。 而判断两个整数相等的时间复杂度是O(1)O(1)O(1),那么我们自然而然就有一个想法:能否把一个集合“转换成一个整数”,然后进行比较? 在本题中想完美的解决这个问题是很困难的,幸运的是,在允许一定程度的错误的情况下,这个问题是很简单的。 考虑这样一个函数 它满足以下两个性质: 用人话说,f(S)f(S)f(S)是一个哈希函数。 故我们只要对集合进行哈希,每次查询时判断二者的哈希值是否相等即可。 至于哈希函数的设计,有许多方法,这里不在赘述。 利用哈希,时间复杂度可以降到O(n)O(n)O(n)。 以下是参考代码 出题人:周鑫 求数组长度为nnn的bbb的个数 ∑i=1naibi=K−a0\sum_{i=1}^{n} a_{i}b_{i}=K - a_{0} i=1∑naibi=K−a0 010101背包变形。 bib_{i}bi只要两种决策(−1-1−1和111),010101背包也只有两种决策(取或不取)。 考虑动态规划。 设dp[i][j]dp[i][j]dp[i][j]为考虑到第iii个数,且当前值为jjj的方案数,不难写出状态转移方程 dp[i][j]=dp[i−1][j−a[i]]+dp[i−1][j+a[i]]dp[i][j] = dp[i-1][j - a[i]] + dp[i-1][j + a[i]] dp[i][j]=dp[i−1][j−a[i]]+dp[i−1][j+a[i]] 第一个是选择了+1+1+1的决策,第二个是选择了−1-1−1的决策。 显然答案为dp[n][K−a[0]]dp[n][K-a[0]]dp[n][K−a[0]] 但是直接这么做会有一个问题:下标会是负数。 有两种方案可以解决这个问题: 时间复杂度为O(n×(n×max(∣ai∣)+K))O(n\times (n\times \mathcal{max}(|a_i |)+ K))O(n×(n×max(∣ai∣)+K)) 值得一提的是这个过程可以利用滚动数组优化空间复杂度,但是在本题中并没有卡大家的空间复杂度。 以下是代码(使用滚动数组和刷表法,故写法可能跟上述描述有点不同)。 出题人:周鑫 给出一个长度为nnn的数组hhh和bbb,找到一个长度为kkk的序列ppp,满足以下条件 只需输出∑i=1nbpi\sum_{i = 1}^{n} b_{p_{i}}∑i=1nbpi即可。 注意到bib_ibi的值很小,我们可以把这个问题转化一下。 对于每个导弹 我们可以把它拆成若干个数 具体为 按照原来顺序组合成一个新的数组ddd。 容易发现,ddd的最长上升子序列就是题目的答案。 时间复杂度为O((n+∑i=1nbi)log(n+∑i=1nbi))O((n + \sum_{i =1 }^{n} b_{i} )\log({n + \sum_{i =1 }^{n} b_{i} }) )O((n+∑i=1nbi)log(n+∑i=1nbi)) 参考代码 考虑动态规划 设dpidp_{i}dpi为从第111个考虑到第iii个答案的最大值,容易写出状态转移方程 dpi=max(dpj+bi)(hi>hj)dp_{i} = \max(dp_{j} + b_{i}) \quad (h_{i} > h_{j}) dpi=max(dpj+bi)(hi>hj) 利用离散化和线段树可以将时间复杂度优化到O(nlogn)O(n\log n)O(nlogn), 这里不在赘述。 出题人:林贝宁 描述:把只包含质因子2、3和5的数称作贝贝数(Ugly Number)。例如6、8都是贝贝数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个贝贝数。求按从小到大的顺序的第N个贝贝数。 出题人:林贝宁 大意:定义波浪形序列为:序列中间的每个数都大于他的相邻的数或者小于他相邻的数。大小定义为字典序大小,求长度为n的序列中第k个波浪型的序列。 故每一个P(n−1,j,0)P(n-1,j,0)P(n−1,j,0)都可以变换为唯一一个P(n,i,1)P(n,i,1)P(n,i,1),其中i≤j≤n−1i\le j\le n-1i≤j≤n−1,即状态转移方程为dpn,i,1=∑j=in−1dpn−1,j,0dp_{n,i,1}=\displaystyle \sum_{j=i}^{n-1} dp_{n-1,j,0}dpn,i,1=j=i∑n−1dpn−1,j,0 此处写了实现类,需要选手自己调用#include
[2] 博丽神社例大祭
题意
思路
代码
c++
代码。#include
java
代码。import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;class Info {Info() {}Info(int x, int y) { this.x = x; this.y = y; }public int x, y;
}public class Main {static Scanner cin = new Scanner(System.in);static PrintWriter cout = new PrintWriter(System.out);public static void main(String[] args) {Solve();cin.close();cout.close();}public static void Solve() {int n = cin.nextInt(), k = cin.nextInt();int[][] dis = new int[n + 2][n + 2];for (int i = 1; i <= n; i ++) {dis[i][0] = dis[0][i] = dis[n + 1][i] = dis[i][n + 1] = 0;for (int j = 1; j <= n; j ++) {dis[i][j] = Integer.MAX_VALUE;}}Queue
py
代码。import queueinf = 1 << 30def Solve() -> None:n, k = map(int, input().split())a = [[False] * (n + 2) for i in range(n + 2)]dis = [[inf] * (n + 2) for i in range(n + 2)]q = queue.Queue()for i in range(0, n + 2):dis[i][0] = dis[0][i] = dis[n + 1][i] = dis[i][n + 1] = 0for i in range(k):x, y = map(int, input().split())a[x][y] = Truedis[x][y] = 0q.put((x, y))D = [(-1, 0), (1, 0), (0, -1), (0, 1)]while not q.empty():x, y = q.get()for dx, dy in D:nx = x + dx; ny = y + dyif dis[nx][ny] == inf:dis[nx][ny] = dis[x][y] + 1q.put((nx, ny))ans = 0for i in range(1, n + 1):for j in range(1, n + 1):ans += dis[i][j]print(ans)return Noneif __name__ == '__main__':Solve()
[3] 无所谓,我会出手
题意
思路
No
可以骗两分。虽然一般比赛会避免只输出一个 Yes / No
的情况,但是如果写不出正解,可以尝试写一些朴素算法或者判断一些特殊情况骗分 (仅限于有部分分数的比赛)。代码实现
C++ 实现 (1)
#include
C++ 实现 (2)
#include
Java 实现
import java.io.PrintWriter;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;public class Main {static Scanner cin = new Scanner(System.in);static PrintWriter cout = new PrintWriter(System.out);public static void main(String[] args) {Solve();cin.close();cout.close();}public static void Solve() {int n = cin.nextInt(), a = cin.nextInt(), d = cin.nextInt(), t = cin.nextInt();if (a > d || a > t) {cout.println("No");return;}int ans = 0;Queue
Python 实现
from collections import dequedef Solve() -> None:n, a, d = map(int, input().split())t = int(input())if a > d or a > t:print("No")returnans = 0q = deque()for i in range(t - a, t, 1):q.append(i); ans += 1for i in range(1, n, 1):t = int(input())while len(q) > 0:tmp = q.popleft()if tmp + d >= t:q.appendleft(tmp)breakadd = a - len(q)for j in range(t - add, t, 1):q.append(j); ans += 1print("Yes")print(ans)return Noneif __name__ == '__main__':Solve()
中档题
[1] 数据结构大师
606060分做法
100100100分解法111
S=(A∪B)−(A∩B)S = (A \cup B) - (A \cap B) S=(A∪B)−(A∩B)#include
100100100分解法222
f:S→Nf: S \rightarrow \text{N} f:S→N#include
[2] 小学计算题
题意
其中bi∈{−1,1}b_{i} \in \{-1,1\}bi∈{−1,1}。做法
#include
动态规划的map实现代码
贝
给定的带log
的map
做法(每一层都是跑不满的,最初的时限也可以过)#include
难题
[1] 导弹拦截特别版
题意
满分做法111
ai×10+0,ai×10+1,ai×10+2,⋮ai×10+bi−1\begin{aligned} &a_{i}\times 10 +0 , \\ &a_{i}\times 10 +1 , \\ &a_{i}\times 10 +2 ,\\ &\vdots \\ &a_{i} \times 10 + b_{i} -1 \\ \end{aligned} ai×10+0,ai×10+1,ai×10+2,⋮ai×10+bi−1#include
满分做法222
[2] Kth-Number
题目陈述
分数设置
set
做法,但是不会用给定的类10/2510/2510/25分 C++API
,一定程度上考查了选手现场使用、学习文档的能力set
做法,且会用给定的类,不会离线,14/2514/2514/25分set
做法,且会用给定的类,会离线,18/2518/2518/25分算法一:质因数分解(暴力)
算法实现
复杂度分析
算法二:集合/优先队列
思路引入
思路推进
考虑复杂度
实现
#include
算法三:三指针做法+离线
算法思路
[1~i]
个贝贝数,那么将u1∼uiu_1\sim u_iu1∼ui每个数都会乘以3,5,7再次放入一个队列中代码实现
v[i]*2==v[j]*3
这样的情况,这种情况我们就需要同时移动i,j#include
压轴题:Kth-Wave
题目陈述
算法一:朴素算法(暴力)
算法思路
代码实现
typedef long long LL;
typedef vector
复杂度分析
算法二:数位DP+set维护
算法思路
思路推进
打表
1 3 2 4
1 4 2 3
2 1 4 3
2 3 1 4
2 4 1 3
3 1 4 2
3 2 4 1
3 4 1 2
4 1 3 2
4 2 3 1
1 3 2 5 4
1 4 2 5 3
1 4 3 5 2
1 5 2 4 3
1 5 3 4 2
2 1 4 3 5
2 1 5 3 4
2 3 1 5 4
2 4 1 5 3
2 4 3 5 1
2 5 1 4 3
2 5 3 4 1
3 1 4 2 5
3 1 5 2 4
3 2 4 1 5
3 2 5 1 4
3 4 1 5 2
3 4 2 5 1
3 5 1 4 2
3 5 2 4 1
4 1 3 2 5
4 1 5 2 3
4 2 3 1 5
4 2 5 1 3
4 3 5 1 2
4 5 1 3 2
4 5 2 3 1
5 1 3 2 4
5 1 4 2 3
5 2 3 1 4
5 2 4 1 3
序列的变换——状态转移方程
dpn,i,0=∑j=1i−1dpn−1,j,1dp_{n,i,0}=\displaystyle \sum_{j=1}^{i-1} dp_{n-1,j,1}dpn,i,0=j=1∑i−1dpn−1,j,1
{1,3,2,4}-->{2,1,3,2,4}
那么他是不是一个长度为5的序列?{2,1,3,5,4}
,肯定有读者想问显然这依旧不是一个波浪形序列?{2,1,3,5,4}-->{2,1,5,3,4}
将5和3、4中小的那个交换,这样就得到了一个下降序列{1,3,2,4}-->{2,1,5,3,4}
{1,4,2,3}-->{2,1,4,3,5}
上升序列的DP方程
dpn,i,1=∑j=in−1dpn−1,j,0dp_{n,i,1}=\displaystyle \sum_{j=i}^{n-1} dp_{n-1,j,0}dpn,i,1=j=i∑n−1dpn−1,j,0对于j==i的变换方式
2 1 4 3-->2 5 1 4 3
,对于P(n-1,i,0),只需要在i后面添加上n,因为n必然是最大的,所以也就变成了上升序列对于j>i,且i的原位置是山顶
{3,4,1,2}-->{2,3,4,1,2}
{2,3,4,1,2}-->{2,3,4,1,5}
对于j>i,且i的原位置是山谷
{3,2,4,1}-->{2,3,2,4,1}-->{2,3,5,4,1}-->{2,5,3,4,1}
再次推进
dpn,i,0=∑j=1i−1dpn−1,j,1dp_{n,i,0}=\displaystyle \sum_{j=1}^{i-1} dp_{n-1,j,1}dpn,i,0=j=1∑i−1dpn−1,j,1
dpn,i,1=∑j=in−1dpn−1,j,0dp_{n,i,1}=\displaystyle \sum_{j=i}^{n-1} dp_{n-1,j,0}dpn,i,1=j=i∑n−1dpn−1,j,0复杂度分析
代码实现
C++
#include
python
class Solution:def stick(self, n, k):inc = []ans = []now = 0dec =[[0 for i in range(n + 1)] for j in range(n + 1)]#python不能用连环等号#如果此处用连续等号,后面的dp数组会有问题inc = [[0 for i in range(n + 1)] for j in range(n + 1)] # n+1个n+1个0,二维数组inc[1][1] = 1dec[1][1] = 1 # 初始长度为1vis = [0 for i in range(n + 1)]for Len in range(2, n + 1): # 长度从2到nfor i in range(1, Len + 1): # 开头的数字从1到Lenfor m in range(1, i): # 下降由上升1-(i-1)的和转移过来dec[Len][i] += inc[Len - 1][m]for m in range(i, Len): # 上升由下降i-(Len-1)的和转移过来inc[Len][i] += dec[Len - 1][m]for i in range(1, n + 1): # i从1到n,当前需要枚举的位置m = 0now = 0Len =n-i+1#剩余需要枚举的长度for j in range(1, n + 1):if (not vis[j]): # 没有访问过m += 1#相当于C++中的set来储存#第i层计算ans中的第i个数,下标为ans[i-1]if i == 1:now = inc[Len][m] + dec[Len][m]elif (j > ans[i - 2] and (i == 2 or ans[i - 2] < ans[i - 3])):#当前位置是山顶,即开头递减now=dec[Len][m]elif (j
下一篇:加密技术和二维码