蓝桥杯 2021年国赛真题
C/C++ 大学C组

  • 试题 A: 整数范围
  • 试题 B: 带宽
  • 试题 C: 纯质数
  • 试题 D: 完全日期
  • 试题 E: 最小权值
  • 试题 F: 大写
  • 试题 G: 123
  • 试题 H: 异或变换
  • 试题  I: 巧克力
  • 试题 J: 二进制问题

  蓝桥杯个人赛软件类历届真题及其解析

  省流,十道签到题。


试题 A: 整数范围

本题总分:555 分


【问题描述】

  用 888 位二进制(一个字节)来表示一个非负整数,表示的最小值是 000,则一般能表示的最大值是多少?

【答案提交】

  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


255


#include <stdio.h>int main() {printf("%d", 0xff);
}

  ¿¿¿


试题 B: 带宽

本题总分:555 分


【问题描述】

  小蓝家的网络带宽是 200200200 Mbps\mathrm{Mbps}Mbps,请问,使用小蓝家的网络理论上每秒钟最多可以从网上下载多少 MB\mathrm{MB}MB 的内容。

【答案提交】

  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


25


#include <stdio.h>int main() {printf("%d", 200 / 8);
}

  ps\mathrm{ps}ps 意为 persecond\mathrm{per\ second}per second,1B=8b1\mathrm{B} = 8\mathrm{b}1B=8b。


试题 C: 纯质数

本题总分:101010 分


【问题描述】

  如果一个正整数只有 111 和它本身两个约数,则称为一个质数(又称素数)。

  前几个质数是:::2,3,5,7,11,13,17,19,23,29,31,37,⋯2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,\cdots2,3,5,7,11,13,17,19,23,29,31,37,⋯。

  如果一个质数的所有十进制数位都是质数,我们称它为纯质数。例如:::2,3,5,7,23,372, 3, 5, 7, 23, 372,3,5,7,23,37 都是纯质数,而 11,13,17,19,29,3111, 13, 17, 19, 29, 3111,13,17,19,29,31 不是纯质数。当然 1,4,351, 4, 351,4,35 也不是纯质数。

  请问,在 111 到 202106052021060520210605 中,有多少个纯质数?

【答案提交】

  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


1903


#include <stdio.h>const int N = 20210605;int ans, composite[N + 1];int check(int n) {if (n < 10) return n == 2 || n == 3 || n == 5 || n == 7;doif (!check(n % 10)) return 0;while (n /= 10);return 1;
}int main() {for (int i = 2; i <= N; ++i)if (!composite[i]) {for (int j = i + i; j <= N; j += i) composite[j] = 1;if (check(i)) ++ans;}printf("%d", ans);
}

  埃拉托色尼筛选法。


试题 D: 完全日期

本题总分:101010 分


【问题描述】

  如果一个日期中年月日的各位数字之和是完全平方数,则称为一个完全日期。

  例如:::202120212021 年 666 月 555 日的各位数字之和为 2+0+2+1+6+5=162 + 0 + 2 + 1 + 6 + 5 = 162+0+2+1+6+5=16,而 161616 是一个完全平方数,它是 444 的平方。所以 202120212021 年 666 月 555 日是一个完全日期。

  例如:::202120212021 年 666 月 232323 日的各位数字之和为 2+0+2+1+6+2+3=162 + 0 + 2 + 1 + 6 + 2 + 3 = 162+0+2+1+6+2+3=16,是一个完全平方数。所以 202120212021 年 666 月 232323 日也是一个完全日期。

  请问,从 200120012001 年 111 月 111 日到 202120212021 年 121212 月 313131 日中,一共有多少个完全日期?

【答案提交】

  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


977


#include <stdio.h>int ans, days[]{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};int is_leap(int year) { return !(year % 100 ? year % 4 : year % 400); }int calc(int n) {int res = 0;dores += n % 10;while (n /= 10);return res;
}int check(int n) {switch (n) {case 1:case 4:case 9:case 16:case 25:case 36: return 1;}return 0;
}int main() {for (int year = 2001; year <= 2021; ++year)for (int month = 1; month <= 12; ++month) {if (is_leap(year)) days[2] = 29;for (int day = 1; day <= days[month]; ++day)if (check(calc(year) + calc(month) + calc(day))) ++ans;days[2] = 28;}printf("%d", ans);
}

  签到 ×4\times\ 4× 4。


试题 E: 最小权值

本题总分:151515 分


【问题描述】

  对于一棵有根二叉树 TTT,小蓝定义这棵树中结点的权值 W(T)W(T)W(T) 如下:::

  空子树的权值为 000。

  如果一个结点 vvv 有左子树 LLL,右子树 RRR,分别有 C(L)C(L)C(L) 和 C(R)C(R)C(R) 个结点,则 W(v)=1+2W(L)+3W(R)+(C(L))2C(R)W(v) = 1 + 2W(L) + 3W(R) + (C(L))^2C(R)W(v)=1+2W(L)+3W(R)+(C(L))2C(R)。

  树的权值定义为树的根结点的权值。

  小蓝想知道,对于一棵有 202120212021 个结点的二叉树,树的权值最小可能是多少?

【答案提交】

  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


2653631372


动态规划


#include <stdio.h>#define min(a, b) (a < b ? a : b)const int N = 2021;long long dp[N + 1];int main() {for (int i = 1; i <= N; ++i) {dp[i] = 0x3f3f3f3f3f3f3f3f;for (int l = 0; l < i; ++l)dp[i] = min(dp[i], 1 + 2 * dp[l] + 3 * dp[i - l - 1] + l * l * (i - l - 1));}printf("%lld", dp[N]);
}

  设 fif_ifi​ 为 C(T)=iC(T) = iC(T)=i 的有根二叉树 TTT 的最小权值,显然 fif_ifi​ 无后效性,故考虑动态规划,有转移方程:::fi=min⁡(1+2fl+3fr+l2r),i=l+r+1,l,r∈Nf_i = \min(1 + 2f_l + 3 f_r + l^2r),\quad i = l + r + 1,\quad l,r \in \mathbb Nfi​=min(1+2fl​+3fr​+l2r),i=l+r+1,l,r∈N  初始时 f0=0f_0 = 0f0​=0,答案为 f2021f_{2021}f2021​。


试题 F: 大写

时间限制: 1.0s1.0\mathrm s1.0s 内存限制: 256.0MB256.0\mathrm{MB}256.0MB 本题总分:151515 分


【问题描述】

  给定一个只包含大写字母和小写字母的字符串,请将其中所有的小写字母转换成大写字母后将字符串输出。

【输入格式】

  输入一行包含一个字符串。

【输出格式】

  输出转换成大写后的字符串。

【样例输入】

LanQiao

【样例输出】

LANQIAO

【评测用例规模与约定】

  对于所有评测用例,字符串的长度不超过 100100100。


#include <stdio.h>#define upper(a) a >= 'a' && a <= 'z' ? a - 0x20 : aint main() {for (int a; ~(a = getchar());) putchar(upper(a));
}

  签到 ×6\times\ 6× 6,几个常用的 ASCII\mathrm{ASCII}ASCII 码 需要记住,

  像 000 对应 0x300\mathrm x300x30;A\mathrm AA 对应 0x410\mathrm x410x41;a\mathrm aa 对应 0x610\mathrm x610x61,

  且数字字母字符在 ASCII\mathrm{ASCII}ASCII 码 表中是自然连续的。


试题 G: 123

时间限制: 1.0s1.0\mathrm s1.0s 内存限制: 256.0MB256.0\mathrm{MB}256.0MB 本题总分:202020 分


【问题描述】

  小蓝发现了一个有趣的数列,这个数列的前几项如下:::

  1,1,2,1,2,3,1,2,3,4,⋯1, 1, 2, 1, 2, 3, 1, 2, 3, 4, \cdots1,1,2,1,2,3,1,2,3,4,⋯

  小蓝发现,这个数列前 111 项是整数 111,接下来 222 项是整数 111 至 222,接下来 333 项是整数 111 至 333,接下来 444 项是整数 111 至 444,依次类推。

  小蓝想知道,这个数列中,连续一段的和是多少。

【输入格式】

  输入的第一行包含一个整数 TTT,表示询问的个数。

  接下来 TTT 行,每行包含一组询问,其中第 iii 行包含两个整数 lil_ili​ 和 rir_iri​,表示询问数列中第 lil_ili​ 个数到第 rir_iri​ 个数的和。

【输出格式】

  输出 TTT 行,每行包含一个整数表示对应询问的答案。

【样例输入】

3
1 1
1 3
5 8

【样例输出】

1
4
8

【评测用例规模与约定】

  对于 10%10\%10% 的评测用例,1≤T≤30,1≤li≤ri≤1001 ≤ T ≤ 30, 1 ≤ l_i ≤ r_i ≤ 1001≤T≤30,1≤li​≤ri​≤100。
  对于 20%20\%20% 的评测用例,1≤T≤100,1≤li≤ri≤10001 ≤ T ≤ 100, 1 ≤ l_i ≤ r_i ≤ 10001≤T≤100,1≤li​≤ri​≤1000。
  对于 40%40\%40% 的评测用例,1≤T≤1000,1≤li≤ri≤1061 ≤ T ≤ 1000, 1 ≤ l_i ≤ r_i ≤ 10^61≤T≤1000,1≤li​≤ri​≤106。
  对于 70%70\%70% 的评测用例,1≤T≤10000,1≤li≤ri≤1091 ≤ T ≤ 10000, 1 ≤ l_i ≤ r_i ≤ 10^91≤T≤10000,1≤li​≤ri​≤109。
  对于 80%80\%80% 的评测用例,1≤T≤1000,1≤li≤ri≤10121 ≤ T ≤ 1000, 1 ≤ l_i ≤ r_i ≤ 10^{12}1≤T≤1000,1≤li​≤ri​≤1012。
  对于 90%90\%90% 的评测用例,1≤T≤10000,1≤li≤ri≤10121 ≤ T ≤ 10000, 1 ≤ l_i ≤ r_i ≤ 10^{12}1≤T≤10000,1≤li​≤ri​≤1012。
  对于所有评测用例,1≤T≤100000,1≤li≤ri≤10121 ≤ T ≤ 100000, 1 ≤ l_i ≤ r_i ≤ 10^{12}1≤T≤100000,1≤li​≤ri​≤1012。


容斥原理


  令该数列为 AAA,显然对于每个回答 ∑i=lrai\sum_{i=l}^ra_i∑i=lr​ai​ 可变化为 ∑i=1rai−∑i=1l−1ai\sum_{i=1}^ra_i - \sum_{i=1}^{l-1}a_i∑i=1r​ai​−∑i=1l−1​ai​,同时构造数列 SSS,∑i=1ksi=∑i=1k(k+1)/2ai\sum_{i=1}^ks_i = \sum_{i=1}^{k(k + 1)/2} a_i∑i=1k​si​=∑i=1k(k+1)/2​ai​,并定义 l′l'l′ 满足 l=l′(l′+1)/2l = l'(l' + 1) / 2l=l′(l′+1)/2,容易将回答再变化为 ∑i=1r′si−∑i=1l′−ξsi\sum_{i=1}^{r'}s_i - \sum_{i=1}^{l'-\xi}s_i∑i=1r′​si​−∑i=1l′−ξ​si​,不过 l′、r′l'、r'l′、r′ 都可能不为正整数,但容易发现 sk=ak(k−1)/2+1+ak(k−1)/2+2+⋯+ak(k+1)/2s_k = a_{k(k-1)/2+1} + a_{k(k-1)/2+2} + \cdots +a_{k(k+1)/2}sk​=ak(k−1)/2+1​+ak(k−1)/2+2​+⋯+ak(k+1)/2​,因此在此基础上添加一点点细节,将 AAA 的前缀和变化为:::calci=∑j=1iaj=∑j=1⌊i′⌋si+∑j=1i−⌊i′⌋aj,\mathrm{calc}_i = \sum_{j=1}^ia_j = \sum_{j=1}^{\lfloor i'\rfloor}s_i + \sum_{j=1}^{i-\lfloor i'\rfloor}a_j,calci​=j=1∑i​aj​=j=1∑⌊i′⌋​si​+j=1∑i−⌊i′⌋​aj​,  最终,答案为:::ansl,r=calcr−calcl−1.\mathrm{ans}_{l,r}=\mathrm{calc}_r - \mathrm{calc}_{l-1}.ansl,r​=calcr​−calcl−1​.

#include <stdio.h>
#include <algorithm>
#include <math.h>const int N = sqrt(2e12) + 9;typedef long long ll;ll A[N], S[N], l, r;ll calc(ll n) {ll *K = std::upper_bound(A, A + N, n) - 1;return S[K - A] + A[n - *K];
}int T;int main() {for (int i = 0; i < N; ++i)A[i] = A[i - 1] + i,S[i] = S[i - 1] + A[i];for (scanf("%d", &T); T--;) {scanf("%lld %lld", &l, &r);printf("%lld\n", calc(r) - calc(l - 1));}
}

试题 H: 异或变换

时间限制: 1.0s1.0\mathrm s1.0s 内存限制: 256.0MB256.0\mathrm{MB}256.0MB 本题总分:202020 分


【问题描述】

  小蓝有一个 010101 串 s=s1s2s3⋅⋅⋅sns = s_{1} s_{2} s_{3} · · · s_{n}s=s1​s2​s3​⋅⋅⋅sn​。

  以后每个时刻,小蓝要对这个 010101 串进行一次变换。每次变换的规则相同。

  对于 010101 串 s=s1s2s3⋅⋅⋅sns = s_{1} s_{2} s_{3} · · · s_{n}s=s1​s2​s3​⋅⋅⋅sn​,变换后的 010101 串 s′=s1′s2′s3′⋯sn′s' = s'_{1}s'_{2}s'_{3} \cdots s'_{n}s′=s1′​s2′​s3′​⋯sn′​ 为:::

  s1′=s1s'_{1} = s_{1}s1′​=s1​;
  si′=si−1⊕sis'_{i} = s_{i−1} ⊕ s_{i}si′​=si−1​⊕si​。

  其中 a⊕ba ⊕ ba⊕b 表示两个二进制的异或,当 aaa 和 bbb 相同时结果为 000,当 a 和 b不同时结果为 111。

  请问,经过 ttt 次变换后的 010101 串是什么?

【输入格式】

  输入的第一行包含两个整数 n,tn, tn,t,分别表示 010101 串的长度和变换的次数。

  第二行包含一个长度为 nnn 的 010101 串。

【输出格式】

  输出一行包含一个 010101 串,为变换后的串。

【样例输入】

5 3
10110

【样例输出】

11010

【样例说明】
  初始时为 101101011010110,变换 111 次后变为 111011110111101,变换 222 次后变为 100111001110011,变换 333 次后变为 110101101011010。

【评测用例规模与约定】

  对于 40%40\%40% 的评测用例,1≤n≤100,1≤t≤10001 ≤ n ≤ 100, 1 ≤ t ≤ 10001≤n≤100,1≤t≤1000。
  对于 80%80\%80% 的评测用例,1≤n≤1000,1≤t≤1091 ≤ n ≤ 1000, 1 ≤ t ≤ 10^{9}1≤n≤1000,1≤t≤109。
  对于所有评测用例,1≤n≤10000,1≤t≤10181 ≤ n ≤ 10000, 1 ≤ t ≤ 10^{18}1≤n≤10000,1≤t≤1018。


二项式定理


  我们将 010101 串 sss 视为 nnn 维向量,第 iii 个分量为 sis_isi​,容易想到通过模 222 矩阵乘法,对 sss 进行 ttt 次变化,更具体地说:::

  s=(s1,s2,⋯,sn)T,s=(s_1,s_2,\cdots,s_n)^T,s=(s1​,s2​,⋯,sn​)T,

  则变换后的 010101 串 s′s's′ 可以表示为:::

  s′=sAn×n,An×n=(110⋯00011⋯00001⋯00⋮⋮⋮⋱⋮⋮000⋯11000⋯01)(mod2)s'=sA_{n\times n},A_{n\times n}=\begin{pmatrix} 1 & 1 & 0 & \cdots & 0 & 0\\ 0 & 1 & 1 & \cdots & 0 & 0\\ 0 & 0 & 1 & \cdots & 0 & 0\\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots\\ 0 & 0 & 0 & \cdots &1 & 1\\ 0 & 0 & 0 & \cdots &0 & 1 \end{pmatrix}\pmod 2s′=sAn×n​,An×n​=⎝⎜⎜⎜⎜⎜⎜⎜⎛​100⋮00​110⋮00​011⋮00​⋯⋯⋯⋱⋯⋯​000⋮10​000⋮11​⎠⎟⎟⎟⎟⎟⎟⎟⎞​(mod2)

  最终答案为 sAtsA^tsAt,不过 nnn 最大为 1e41e41e4,即使是在快速幂加速的情况下,O(n3log⁡t)O(n^3\log t)O(n3logt) 的复杂度显然无法通过所有测试用例,不过矩阵 AAA 很“工整”,我们将 AAA 拆分为 EEE 与 BBB 之和,即:::

  A=E+B=(100⋯00010⋯00001⋯00⋮⋮⋮⋱⋮⋮000⋯10000⋯01)+(010⋯00001⋯00000⋯00⋮⋮⋮⋱⋮⋮000⋯01000⋯00)A = E + B = \begin{pmatrix} 1 & 0 & 0 & \cdots & 0 & 0\\ 0 & 1 & 0 & \cdots & 0 & 0\\ 0 & 0 & 1 & \cdots & 0 & 0\\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots\\ 0 & 0 & 0 & \cdots &1 & 0\\ 0 & 0 & 0 & \cdots &0 & 1 \end{pmatrix} +\begin{pmatrix} 0 & 1 & 0 & \cdots & 0 & 0\\ 0 & 0 & 1 & \cdots & 0 & 0\\ 0 & 0 & 0 & \cdots & 0 & 0\\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots\\ 0 & 0 & 0 & \cdots &0 & 1\\ 0 & 0 & 0 & \cdots &0 & 0 \end{pmatrix}A=E+B=⎝⎜⎜⎜⎜⎜⎜⎜⎛​100⋮00​010⋮00​001⋮00​⋯⋯⋯⋱⋯⋯​000⋮10​000⋮01​⎠⎟⎟⎟⎟⎟⎟⎟⎞​+⎝⎜⎜⎜⎜⎜⎜⎜⎛​000⋮00​100⋮00​010⋮00​⋯⋯⋯⋱⋯⋯​000⋮00​000⋮10​⎠⎟⎟⎟⎟⎟⎟⎟⎞​

  EEE、BBB 可交换,即 EB=BEEB = BEEB=BE,对二项式 At=(E+B)tA^t = (E + B)^tAt=(E+B)t 展开有 At=∑i=0nCniEn−iBi=∑i=0nCniBiA^t=\displaystyle{\sum_{i=0}^nC_{n}^iE^{n-i}B^i = \sum_{i=0}^nC_{n}^iB^i}At=i=0∑n​Cni​En−iBi=i=0∑n​Cni​Bi,

  而 Bn×n=(bij)n×nB_{n\times n} = (b_{ij})_{n\times n}Bn×n​=(bij​)n×n​,bij={1i=j−10otherwise,b_{ij}=\begin{cases}1 &i=j-1\\0&otherwise\end{cases},bij​={10​i=j−1otherwise​,

  根据矩阵乘法的定义,(cij)n×m=(aij)n×k(bij)k×m(c_{ij})_{n\times m}=(a_{ij})_{n\times k}(b_{ij})_{k\times m}(cij​)n×m​=(aij​)n×k​(bij​)k×m​,cij=∑g=1kaigbgjc_{ij} = \sum_{g=1}^ka_{ig}b_{gj}cij​=∑g=1k​aig​bgj​,则 ggg 确定时,(dij)=B2(d_{ij}) = B^2(dij​)=B2,i=j−2i = j - 2i=j−2 时 dijd_{ij}dij​ 才非零,类似的我们可以得到结论:::Bn=(bij),bij={1i=j−n0otherwise,B^n = (b_{ij}),\quad b_{ij}=\begin{cases}1 &i=j-n\\0&otherwise\end{cases},Bn=(bij​),bij​={10​i=j−notherwise​,  容易找到 AnA^nAn 的通项公式:::An=(aij),aij{0i<jCnj−iotherwiseA^n = (a_{ij}),\quad a_{ij}\begin{cases}0 &i<j\\C_n^{j-i}&otherwise\end{cases}An=(aij​),aij​{0Cnj−i​​i<jotherwise​  再根据组合数性质:有组合数 CnmC_n^mCnm​,定义 n&mn\ \&\ mn & m 为二进制表示下,nnn、mmm 按位相与,则若 n&m=mn\ \&\ m = mn & m=m,CnmC_n^mCnm​ 为奇数,否则则为偶数,即可在 O(n2)O(n^2)O(n2) 复杂度下完成 sAt(mod2)sA^t\pmod 2sAt(mod2) 的计算。


  证明:::

  首先 [Cnm=[C_n^m=[Cnm​= 偶数]⇔[2∣Cnm]] \Leftrightarrow [2 \mid C_n^m]]⇔[2∣Cnm​],

  而 Cnm=n!m!(n−m)!C_n^m = \cfrac{n!}{m!(n-m)!}Cnm​=m!(n−m)!n!​,令 a、b、ca、b、ca、b、c 分别为 n!、m!、(n−m)!n!、m!、(n-m)!n!、m!、(n−m)! 中因子 222 的个数,则 [Cnm=[C_n^m=[Cnm​= 偶数]⇔[a>b+c]] \Leftrightarrow[a > b + c]]⇔[a>b+c],

  笔者在 十三届省赛 求阶乘 中给出过一种计算某个阶乘给定因子个数的公式,即有 a=∑i=1⌊log⁡2n⌋⌊n2i⌋a = \displaystyle{\sum_{i=1}^{\lfloor\log_2 n\rfloor}\left\lfloor\frac n{2^i}\right\rfloor}a=i=1∑⌊log2​n⌋​⌊2in​⌋,

  若 n&m=mn\ \&\ m = mn & m=m 成立,则 ⌊n2k⌋=⌊m2k⌋+⌊n−m2k⌋\displaystyle{\left\lfloor\frac n{2^k}\right\rfloor = \left\lfloor\frac m{2^k}\right\rfloor + \left\lfloor\frac {n - m}{2^k}\right\rfloor}⌊2kn​⌋=⌊2km​⌋+⌊2kn−m​⌋ 恒成立,同时 a=b+ca = b + ca=b+c 成立,CnmC_n^mCnm​ 为奇数。

  若 n&m=mn\ \&\ m = mn & m=m 不成立,则 m+(n−m)m + (n - m)m+(n−m) 在某一二进制位上会出现进位,设该数位为 kkk,则有 nmod2k<mmod2k+(n−m)mod2kn\ \mathrm{mod}\ 2^k < m\ \mathrm{mod}\ 2^k + (n - m)\ \mathrm{mod}\ 2^kn mod 2k<m mod 2k+(n−m) mod 2k;⌊n2k⌋>⌊m2k⌋+⌊n−m2k⌋\displaystyle{\left\lfloor\frac n{2^k}\right\rfloor > \left\lfloor\frac m{2^k}\right\rfloor + \left\lfloor\frac {n - m}{2^k}\right\rfloor}⌊2kn​⌋>⌊2km​⌋+⌊2kn−m​⌋,故而 a>b+ca > b + ca>b+c 成立,CnmC_n^mCnm​ 为偶数。


#include <stdio.h>#define min(a, b) (a < b ? a : b)char buf[10009];long long t;int n;int main() {scanf("%d %lld %s", &n, &t, buf);for (int i = n - 1; i; --i)for (int j = min(i, t); j; --j)if ((t & j) == j && buf[i - j] == '1') buf[i] ^= 1;printf("%s", buf);
}

试题  I: 巧克力

时间限制: 1.0s1.0\mathrm s1.0s 内存限制: 256.0MB256.0\mathrm{MB}256.0MB 本题总分:252525 分


【问题描述】

  小蓝很喜欢吃巧克力,他每天都要吃一块巧克力。

  一天小蓝到超市想买一些巧克力。超市的货架上有很多种巧克力,每种巧克力有自己的价格、数量和剩余的保质期天数,小蓝只吃没过保质期的巧克力,请问小蓝最少花多少钱能买到让自己吃 x 天的巧克力。

【输入格式】

  输入的第一行包含两个整数 x,nx, nx,n,分别表示需要吃巧克力的天数和巧克力的种类数。

  接下来 nnn 行描述货架上的巧克力,其中第 iii 行包含三个整数 ai,bi,cia_i, b_i, c_iai​,bi​,ci​,表示第 iii 种巧克力的单价为 aia_iai​,保质期还剩 bib_ibi​ 天(从现在开始的 bib_ibi​ 可以吃),数量为 cic_ici​。

【输出格式】

  输出一个整数表示小蓝的最小花费。如果不存在让小蓝吃 xxx 天的购买方案,输出 −1-1−1。

【样例输入】

10 3
1 6 5
2 7 3
3 10 10

【样例输出】

18

【样例说明】
  一种最佳的方案是第 111 种买 555 块,第 222 种买 222 块,第 333 种买 333 块。前 555 天吃第 111 种,第 6、76、76、7 天吃第 222 种,第 888 至 101010 天吃第 333 种。

【评测用例规模与约定】

  对于 30%30\%30% 的评测用例,n,x≤1000n, x ≤ 1000n,x≤1000。
  对于所有评测用例,1≤n,x≤100000,1≤ai,bi,ci≤1091 ≤ n, x ≤ 100000,1 ≤ a_i, b_i, c_i ≤ 10^91≤n,x≤100000,1≤ai​,bi​,ci​≤109。


贪心 + 并查集


  最佳的方案总是可以描述为:尽可能多的选择尽可能便宜的巧克力。

  为此,我们按巧克力价值升序重排,并建立一个数组,标记某天是否有安排巧克力,对于每 111 种巧克力,我们至剩余保质期向前寻找第 111 个未被安排的日期,直至该种巧克力用尽或保质期内的日子都被排满。

  易知每 111 种巧克力可能的安排只会被另一种更优的安排占用,故最终方案最优。

  同时使用查并集去寻找某个时间前第 111 个未被安排的日期,设 xxx 与 nnn 同阶,最终复杂度为 O(xlog⁡x)O(x\log x)O(xlogx)。

#include <stdio.h>
#include <algorithm>#define min(a, b) (a < b ? a : b)const int N = 100001;int n, x, buf, linked[N];long long ans;struct node {int a, b, c;
} choco[N];inline bool cmp(node &n1, node &n2) { return n1.a < n2.a; }int find(int x) { return x == linked[x] ? x : (linked[x] = find(linked[x])); }int main() {scanf("%d %d", &x, &n);for (int i = 0; i < n; ++i)scanf("%d %d %d", &choco[i].a, &choco[i].b, &choco[i].c);for (int i = 1; i <= x; ++i) linked[i] = i;std::sort(choco, choco + n, cmp);for (int i = 0; i < n; ++i) {if (choco[i].b > x) choco[i].b = x;while (buf = find(choco[i].b)) {if (!choco[i].c--) break;linked[buf] = buf - 1;ans += choco[i].a;}}for (int i = 1; i <= x; ++i)if (i == linked[x]) ans = -1;printf("%lld", ans);
}

贪心 + 大根堆


  除了以价值大小为起点外,还可以某个时间范围内为起点考量最佳方案,更具体地说:::

  将巧克力以剩余保质期升序重排,遍历并维护当前巧克力保质期内的最优方案,为此我们建立一个以巧克力价值为关键字大根堆 HHH,对于第 iii 种巧克力,若 ci+∣H∣>bic_i + |H| > b_ici​+∣H∣>bi​,尝试从 HHH 中弹出 ci+∣H∣−bic_i + |H| - b_ici​+∣H∣−bi​ 个巧克力,因为当前巧克力的加入会使堆中方案更优,然后往 HHH 中压入当前巧克力,直至 ∣H∣=bi|H| = b_i∣H∣=bi​ 或当前巧克力用空。

  使用大根堆使得程序可以方便的以种为单位组织巧克力,最终复杂度为 O(nlog⁡n)O(n\log n)O(nlogn)。

#include <stdio.h>
#include <algorithm>
#include <queue>struct node {int a, b;mutable int c;inline bool operator<(const node &n) const { return a < n.a; }
} choco[100000];inline bool cmp(node &n1, node &n2) { return n1.b < n2.b; }std::priority_queue<node> heap;int n, x, cnt, buf;long long ans;int main() {scanf("%d %d", &x, &n);for (int i = 0; i < n; ++i)scanf("%d %d %d", &choco[i].a, &choco[i].b, &choco[i].c);std::sort(choco, choco + n, cmp);for (int i = 0; i < n; ++i) {if (choco[i].b > x) choco[i].b = x;while (heap.size() &&heap.top().a > choco[i].a &&cnt + choco[i].c > choco[i].b) {buf = cnt + choco[i].c - choco[i].b;if (heap.top().c <= buf)cnt -= heap.top().c, heap.pop();else {if (buf > 0) heap.top().c -= buf, cnt -= buf;break;}}if (choco[i].c + cnt > choco[i].b)choco[i].c = choco[i].b - cnt;if (choco[i].c > 0)heap.push(choco[i]), cnt += choco[i].c;}if (cnt < x) puts("-1");else {for (; heap.size(); heap.pop())ans += (long long)heap.top().a * heap.top().c;printf("%lld", ans);}
}

  以普遍理性而论,n≤xn \leq xn≤x 在多数测试点上应当是成立的,不过考虑到数据范围和常数等因素,大根堆实现的贪心性能上应该不优于并查集。


试题 J: 二进制问题

时间限制: 1.0s1.0\mathrm s1.0s 内存限制: 256.0MB256.0\mathrm{MB}256.0MB 本题总分:252525 分


【问题描述】

  小蓝最近在学习二进制。他想知道 111 到 NNN 中有多少个数满足其二进制表示中恰好有 KKK 个 111。你能帮助他吗?

【输入格式】

  输入一行包含两个整数 NNN 和 KKK。

【输出格式】

  输出一个整数表示答案。

【样例输入】

7 2

【样例输出】

3

【评测用例规模与约定】

  对于 30%30\%30% 的评测用例,1≤N≤106,1≤K≤101 ≤ N ≤ 10^6, 1 ≤ K ≤ 101≤N≤106,1≤K≤10。
  对于 60%60\%60% 的评测用例,1≤N≤2×109,1≤K≤301 ≤ N ≤ 2 × 10^9, 1 ≤ K ≤ 301≤N≤2×109,1≤K≤30。
  对于所有评测用例,1≤N≤1018,1≤K≤501 ≤ N ≤ 10^{18}, 1 ≤ K ≤ 501≤N≤1018,1≤K≤50。


数位 dp


  设函数 fN,Kf_{N,K}fN,K​ 表示 111 到 NNN 中满足其二进制表示中恰好有 KKK 个 111 的数的个数,容易得知当 log⁡2N∈Z\log_2 N \in \mathbb Zlog2​N∈Z 成立时,fn=Clog⁡2NKf_n = C_{\log_2 N}^Kfn​=Clog2​NK​,

  因此,我们可以将 NNN 看作 1∼2⌊log⁡2N⌋1 \sim 2^{\lfloor\log_2 N\rfloor}1∼2⌊log2​N⌋ 和 2⌊log⁡2N⌋+1∼N2^{\lfloor\log_2 N\rfloor} + 1 \sim N2⌊log2​N⌋+1∼N 两部分,从第二部分提出常数项 2⌊log⁡2N⌋2^{\lfloor\log_2 N\rfloor}2⌊log2​N⌋,整理可得 fN,K=C⌊log⁡2N⌋K+fN−⌊log⁡2N⌋,K−1f_{N,K} = C_{\lfloor\log_2 N\rfloor}^K + f_{N - \lfloor\log_2 N\rfloor, K - 1}fN,K​=C⌊log2​N⌋K​+fN−⌊log2​N⌋,K−1​。

  可以 数位 dp\mathrm{dp}dp,但没必要。

#include <stdio.h>long long C(int n, int m) {if (m > n) return 0;long long C = 1;for (int i = 0; i < m; ++i)C = C * (n - i) / (i + 1);return C;
}long long n, k, ans;int main() {scanf("%lld %d", &n, &k);for (int i = 63; ~i; --i)if (n >> i & 1) ans += C(i, k--);printf("%lld", ans + !k);
}

  定义 countBit⁡(x)\operatorname{countBit}(x)countBit(x),其意义为统计 xxx 在二进制表示下 111 的个数,即 gcc\mathrm{gcc}gcc 中的__builtin_popcount,当 countBit⁡(N)=K\operatorname{countBit}(N) = KcountBit(N)=K 时,笔者给出的程序会陷入“无法累加 C−10C_{-1}^0C−10​” 的困境中,即无法统计到 NNN 这个符合要求的数,为此最后需要特判一下。

第十二届蓝桥杯大赛软件赛决赛(C/C++ 大学C组)相关推荐

  1. 2021年第十二届蓝桥杯大赛软件赛决赛C/C++大学A组 个人部分题解

    题目下载链接:https://download.csdn.net/download/ljw_study_in_CSDN/19403461 这次国赛,基本上大题都是暴力写的,填空题只写了前两个,老混子选 ...

  2. 第十三届蓝桥杯大赛软件赛决赛(Java 大学C组)

    蓝桥杯 2022年国赛真题 Java 大学C组 试题 A: 斐波那契与 7 试题 B: 小蓝做实验 试题 C: 取模 试题 D: 内存空间 试题 E: 斐波那契数组 试题 F: 最大公约数 试题 G: ...

  3. 第十三届蓝桥杯大赛软件赛决赛(Java 大学B组)

    蓝桥杯 2022年国赛真题 Java 大学B组  试题 A: 重合次数  试题 B: 数数  试题 C: 左移右移  试题 D: 窗口  试题 E: 迷宫  试题 F: 小球称重  试题 G: 背包与 ...

  4. 第十三届蓝桥杯大赛软件赛决赛(Java 大学A组)

    蓝桥杯 2022年国赛真题 Java 大学A组 试题 A: 火柴棒数字 试题 B: 小蓝与钥匙 试题 C: 内存空间 试题 D: 斐波那契数组 试题 E: 交通信号 试题 F: 数组个数 试题 G: ...

  5. 第十二届蓝桥杯大赛软件赛决赛题解

    题目下载链接 注意,以下答案均为作者本人的答案,不是官方答案!!!(也就是说,可能(多半)是错的) 填空预览 25 1903 977 2607074472 试题 A: 带宽 ##[问题描述] 小蓝家的 ...

  6. 2021 第十二届蓝桥杯大赛软件赛决赛, 国赛,C/C++ 大学B 组

    概览 答案提交:01-04 直接做就行 树不太确定,不过感觉是完全二叉树,贪了一个 程序设计:06-10 两个15分题,大小写是送的.123开始暴力,后来想到的前缀和优化,再后来想到了O(1)找到区块 ...

  7. 第十二届蓝桥杯大赛软件赛省赛 C/C++ 大学 B 组解析

    第十二届蓝桥杯大赛软件赛省赛 C/C++ 大学 B 组 试题 A: 空间 试题 B: 卡片 试题 C: 直线 试题 D: 货物摆放 试题 E: 路径 试题 F: 时间显示 试题 G: 砝码称重 试题 ...

  8. 第十二届蓝桥杯大赛软件赛省赛 Java 大学 B 组(2021年4月18日)

    第十二届蓝桥杯大赛软件赛省赛 Java 大学 B 组第一场 下载原题PDF 欢迎评论区留下答案讨论!!! 试题 A: ASC 本题总分:5 分 [问题描述] 已知大写字母 A 的 ASCII 码为 6 ...

  9. 2021第十二届蓝桥杯大赛软件赛省赛C++ C组真题题解

    ============================== 2019-2021蓝桥杯C++ C组真题题解: 2019第十届蓝桥杯大赛软件类省赛C++ C组真题题解 2020第十一届蓝桥杯大赛软件类省 ...

最新文章

  1. linux y脚本,Linux中脚本的使用方法
  2. 如何检查电脑是否安装了python-python-如何检查安装了scikit的nltk版本?
  3. jmap, jhat, jvisualvm:java堆内存对象分析利器
  4. 看一下CDI 2.0 EDR1
  5. LeetCode 第 23 场双周赛(970/2044,前47.5%)
  6. 计算机考试的基础知识高考,计算机考试基础知识试题..doc
  7. CREELINKS平台_处理器CeAd资源使用说明(CeAd的配置与使用)
  8. 为增强软件供应链安全,NIST 发布《开发者软件验证最低标准指南》
  9. java 8 map reduce_java8之Lambda表达式 4:MapReduce开发案例
  10. 从安装、管理到防御,阿里云安骑士全向测评
  11. 从零开始配置vim(22)——lsp简介与treesitter 配置
  12. android的NDK安装及工程实例
  13. 进入ubuntu进入系统时忘记密码了怎么办
  14. 这篇文章终于把中美德三国的工业互联网讲清楚了
  15. pytorch动态网络以及权重共享
  16. Nginx基本使用和代理服务器(负载均衡)--保姆级教程
  17. 计算机类专业工程认证,我校计算机科学与技术、测绘工程专业通过中国工程教育专业认证...
  18. java如何实现aes加密_Java 如何实现AES加密
  19. Matlab绘制幅值谱和相位谱
  20. 能够更便捷管理菜单栏图标的Bartender 4 Mac中文版

热门文章

  1. 0-机器学习-深度学习-入门建议-章浩
  2. sw2urdf插件安装提示
  3. python怎么读字意思是什么_python英文怎么读
  4. Android 拍照或从相册取图片并裁剪
  5. 为什么要论文查重呢?
  6. Edge浏览器访问特殊网站端口(如10080)出现ERR_UNSAFE_PORT解决办法
  7. html5游戏ztype源码,新款HTML5游戏Z-type考验玩家的打字速度
  8. 【开发工具】IntelliJ中高效重构的 10 个快捷方式
  9. 数据分析1——系统认识数据分析
  10. poi使用模板导出word带图片