蓝桥杯 2023年省赛真题
Java 大学A组
试题 A: 特殊日期
试题 B: 与或异或
试题 I: 高塔
把填空挂上跟大伙对对答案,然后 I \rm I I 题出的还行就先讲讲,剩下的最近有点忙,先放放。
试题 A: 特殊日期
本题总分:5 分
【问题描述】
记一个日期为 y y \small yy yy 年 m m \small mm mm 月 d d \small dd dd 日,统计从 2000 \small 2000 2000 年 1 \small 1 1 月 1 \small 1 1 日到 2000000 \small 2000000 2000000 年 1 \small 1 1 月 1 \small 1 1 日,有多少个日期满足年份 y y \small yy yy 是月份 m m \small mm mm 的倍数,同时也是 d d \small dd dd 的倍数。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
35813063
朴素解法
考虑到以日为单位计量,时间段的阶并不大,因此直接使用java.time.LocalDate
模拟日期变化,判断然后累加,程序在笔者
P
C
\small\rm PC
PC 运行
15
\small15
15 秒后得到了答案。
import java.time.LocalDate;
public class Main {
public static void main(String ...args) { new Main().run(); }
LocalDate start = LocalDate.of(2000, 1, 1);
LocalDate end = LocalDate.of(2000000, 1, 1);
void run() {
long ans = 0;
for (LocalDate i = start; i.compareTo(end) <= 0; i = i.plusDays(1))
if (i.getYear() % i.getMonthValue() == 0
&& i.getYear() % i.getDayOfMonth() == 0) ++ans;
System.out.println(ans);
}
}
倍数法
设函数 f y ( x ) = { 1 x ∣ y 0 o t h e r w i s e \small f_y(x) = \begin{cases} 1 & x\,|\,y\\ 0 & \rm otherwise \end{cases} fy(x)={10x∣yotherwise,对于正整数 y \small y y,记 d y \small d_y dy为 ∑ x = 1 31 f y ( x ) \sum_{x=1}^{31}\small f_y(x) ∑x=131fy(x), m y \small m_y my为 ∑ x = 1 12 f y ( x ) \sum_{x=1}^{12}\small f_y(x) ∑x=112fy(x),则在不考虑日期是否合法的情况下,答案为 ∑ y = 2000 2000000 − 1 d y ⋅ m y + 1 \sum_{y=2000}^{2000000 - 1}\small \operatorname{d}_y\cdot\operatorname{m}_y+1 ∑y=20002000000−1dy⋅my+1。因此我们用倍数法在线性时间复杂度意义下求出 d d d 与 m m m,将答案拆分成若干合法部分累加,最后得到正确答案。
import java.util.function.IntPredicate;
import java.util.stream.IntStream;
public class Main {
public static void main(String ...args) { new Main().run(); }
void run() {
System.out.println(
calc(IntStream.rangeClosed(1, 12), IntStream.range(1, 29), y -> true)
+ calc(IntStream.of(2), IntStream.of(29), y -> y % 100 == 0 ? (y % 400 == 0) : (y % 4 == 0))
+ calc(IntStream.iterate(1, m -> m == 1 ? 3 : m + 1).limit(11), IntStream.rangeClosed(29, 30), y -> true)
+ calc(IntStream.of(1, 3, 5, 7, 8, 10, 12), IntStream.of(31), y -> true)
+ 1
);
}
final int start = 2000, end = 2000000;
int calc(IntStream m, IntStream d, IntPredicate yf) {
int[] my = new int[end + 1];
int[] dy = new int[end + 1];
m.forEach(
a -> {
for (int i = 1; i * a <= end; ++i) ++my[i * a];
}
);
d.forEach(
a -> {
for (int i = 1; i * a <= end; ++i) ++dy[i * a];
}
);
return IntStream.range(start, end).filter(yf).map(
a -> my[a] * dy[a]
).sum();
}
}
帅是帅,但放在竞赛中性价比极低,编程多耗费时间都够你针对朴素解法的程序给出好几个测试用例了。
试题 B: 与或异或
本题总分:5 分
【问题描述】
小蓝有一张门电路的逻辑图,如下图所示 : : :
图中每个三角形代表着一种门电路,可能是与门、或门、异或门中的任何一种,它接受上一层中的两个圆形中的数据作为输入,产生一个输出值输出到下一级(如图中箭头所示)。图中圆形表示的是暂存的输出结果,取值只可能是 0 \small 0 0 或 1 \small 1 1,为了便于表示我们用 a r r [ i ] [ j ] \small arr[i][ j] arr[i][j] 表示第 i ( 0 ≤ i ≤ 4 ) \small i(0 ≤ i ≤ 4) i(0≤i≤4) 行第 j ( 0 ≤ j ≤ i ) \small j(0 ≤ j ≤ i) j(0≤j≤i) 个圆形的值。其中 a r r [ 0 ] = ( I n [ 0 ] , I n [ 1 ] , I n [ 2 ] , I n [ 3 ] , I n [ 4 ] ) \small arr[0] = (In[0], In[1], In[2], In[3], In[4]) arr[0]=(In[0],In[1],In[2],In[3],In[4]) 表示的是输入数据,对于某个 a r r [ i ] [ j ] ( i ≤ 0 ) \small arr[i][ j](i ≤ 0) arr[i][j](i≤0),计算方式为 a r r [ i ] [ j ] = a r r [ i − 1 ] [ j ] o p a r r [ i − 1 ] [ j + 1 ] \small arr[i][ j] = arr[i − 1][ j]\ op\ arr[i − 1][ j + 1] arr[i][j]=arr[i−1][j] op arr[i−1][j+1],其中 o p \small op op 表示的是将 a r r [ i − 1 ] [ j ] 、 a r r [ i − 1 ] [ j + 1 ] \small arr[i − 1][ j]、arr[i − 1][ j + 1] arr[i−1][j]、arr[i−1][j+1] 作为输入,将 a r r [ i ] [ j ] \small arr[i][ j] arr[i][j] 作为输出的那个门电路,与门、或门、异或门分别对应于按位与 ( & ) \small (\&) (&)、按位或 ( ∣ ) \small (\:|\:) (∣)、按位异或 ( \small (\, (^ ) \small \,) ) 运算符。
现在已知输入为 I n [ 0 ] = 1 , I n [ 1 ] = 0 , I n [ 2 ] = 1 , I n [ 3 ] = 0 , I n [ 4 ] = 1 \small In[0] = 1, In[1] = 0, In[2] = 1, In[3] = 0, In[4] = 1 In[0]=1,In[1]=0,In[2]=1,In[3]=0,In[4]=1,小蓝想要使得最终的输出 O u t \small Out Out 的值为 1 \small 1 1,请问一共有多少种不同的门电路组合方式?其中上图中显示的就是一种合法的方式。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
30528
深度优先搜索
暴搜杯!我的青春回来了,开搜!
public class Main {
public static void main(String ...args) { new Main().run(); }
int[][] cir = new int[6][6];
int ans = 0, target = 1;
void run() {
cir[5] = new int[]{ 0, 1, 0, 1, 0, 1 };
dfs(1, 5);
System.out.println(ans);
}
void dfs(int i, int n) {
if (n <= 1) {
if (cir[n][i] == target) ++ans;
} else {
if (i < n) {
cir[n - 1][i] = cir[n][i] & cir[n][i + 1];
dfs(i + 1, n);
cir[n - 1][i] = cir[n][i] | cir[n][i + 1];
dfs(i + 1, n);
cir[n - 1][i] = cir[n][i] ^ cir[n][i + 1];
dfs(i + 1, n);
} else {
dfs(1, n - 1);
}
}
}
}
试题 I: 高塔
时间限制:3.0s 内存限制:512.0MB 本题总分:25 分
【问题描述】
小蓝正在玩一个攀登高塔的游戏。高塔的层数是无限的,但游戏最多只有 n \small n n 回合。
小蓝一开始拥有 m \small m m 点能量,在每个回合都有一个值 A i \small A_i Ai 表示小蓝的角色状态。小蓝每回合可以选择消费任意点能量 C i \small C_i Ci (最低消费 1 \small 1 1 点,没有上限),他在这回合将最多可以向上攀爬 A i ⋅ C i \small A_i\cdot C_i Ai⋅Ci 层。实际攀爬的层数取决于小蓝自己在这回合的表现,不过最差也会向上爬一层。
当某回合小蓝的能量点数耗尽,那么在完成这个回合后,游戏结束。 n \small n n 回合结束后,不管能量还有没有剩余,游戏都会直接结束。
给出小蓝每回合的 A i \small A_i Ai 和自己一开始的能量点数 m \small m m。小蓝想知道有多少种不同的可能出现的游玩过程。如果小蓝在两种游玩过程中的任一对应回合花费的能量点数不同或该回合结束时所处层数不同,那么这两种游玩过程就被视为不同。
【输入格式】
输入的第一行包含两个整数 n , m \small n, m n,m,用一个空格分隔。
第二行包含 n \small n n 个整数 A i \small A_i Ai,相邻整数之间使用一个空格分隔,表示小蓝每回合的状态值。
【输出格式】
输出一行包含一个整数表示给定条件下不同游玩过程的数量。由于答案可能很大,你只需要输出答案对 998244353 \small 998244353 998244353 取模的结果
【样例输入】
9 15
3 2 5 7 1 4 6 8 3
【样例输出】
392149233
【评测用例规模与约定】
对于
40
%
\small 40\%
40% 的评测用例,
n
≤
300
,
m
≤
500
\small n ≤ 300,m ≤ 500
n≤300,m≤500;
对于所有评测用例,
1
≤
n
≤
2
×
1
0
5
,
n
≤
m
≤
1
0
18
,
1
≤
A
i
≤
1
0
9
\small 1 ≤ n ≤ 2 × 10^5,n ≤ m ≤ 10^{18},1 ≤ A_i ≤ 10^9
1≤n≤2×105,n≤m≤1018,1≤Ai≤109。
组合数学
为了方便讨论,这里先给出一种小蓝在第 n n n 回合结束游戏的游玩过程数量的计算方法。依题意的,第 i i i 回合小蓝共消耗了 C i C_i Ci,共消耗了 n ≤ ∑ i = 1 n C i ≤ m n \leq\sum_{i=1}^nC_i\leq m n≤∑i=1nCi≤m点能量,第 i i i 回合有 A i ⋅ C i A_i\cdot C_i Ai⋅Ci 总不同的走法,故方案数为: ∑ c 1 , c 2 , ⋯ , c n > 0 c 1 + c 2 + ⋯ + c n ≤ m ∏ i = 1 n A i C i = ∑ c 1 , c 2 , ⋯ , c n > 0 c 1 + c 2 + ⋯ + c n ≤ m ∏ i = 1 n C i ⋅ ∏ i = 1 n A i . \sum_{\substack{c_1,c_2,\cdots,c_n > 0\\c_1+c_2+\cdots+c_n\leq m}}\prod_{i=1}^nA_iC_i=\sum_{\substack{c_1,c_2,\cdots,c_n > 0\\c_1+c_2+\cdots+c_n\leq m}}\prod_{i=1}^nC_i\cdot\prod_{i=1}^nA_i. c1,c2,⋯,cn>0c1+c2+⋯+cn≤m∑i=1∏nAiCi=c1,c2,⋯,cn>0c1+c2+⋯+cn≤m∑i=1∏nCi⋅i=1∏nAi. 记 p ( n , m ) p(n,m) p(n,m) 为 ∑ c 1 , c 2 , ⋯ , c n > 0 c 1 + c 2 + ⋯ + c n ≤ m ∏ i = 1 n C i \sum_{\substack{c_1,c_2,\cdots,c_n > 0\\c_1+c_2+\cdots+c_n\leq m}}\prod_{i=1}^nC_i ∑c1,c2,⋯,cn>0c1+c2+⋯+cn≤m∏i=1nCi。因为在小于 n n n 的回合结束要耗尽能量,所以整理可以知最终答案为: p ( n , m ) ∏ i = 1 n A i + ∑ j = 1 n − 1 ( p ( j , m ) − p ( j , m − 1 ) ) ∏ i = 1 j A i . p(n,m)\prod_{i=1}^nA_i+\sum_{j=1}^{n-1}(p(j,m) -p(j,m-1))\prod_{i=1}^jA_i. p(n,m)i=1∏nAi+j=1∑n−1(p(j,m)−p(j,m−1))i=1∏jAi. 因此该思路下, p ( n , m ) p(n,m) p(n,m) 求解的复杂度与整体直接关联,考虑 p p p 的边界情况,当 n = 1 n=1 n=1 时, p ( 1 , m ) = 1 + 2 + ⋯ + m = m ( m + 1 ) 2 p(1,m) = 1+2+\cdots+m=\cfrac {m(m+1)}2 p(1,m)=1+2+⋯+m=2m(m+1)。考虑 n + 1 n+1 n+1 情况,枚举 C n + 1 C_{n+1} Cn+1 可能的取值 1 , 2 , ⋯ m − n 1,2,\cdots m-n 1,2,⋯m−n,则有递推式: p ( n , m ) = { 1 + 2 + ⋯ + m n = 1 ∑ i = 1 m − n + 1 i p ( i − 1 , m − i ) 1 < n ≤ m . p(n,m) = \begin{cases} 1+2+\cdots+m &n=1 \\ \sum_{i=1}^{m-n+1} ip(i-1,m-i) &1< n\leq m \end{cases}. p(n,m)={1+2+⋯+m∑i=1m−n+1ip(i−1,m−i)n=11<n≤m. 观察到 p ( 1 , m ) = m ( m + 1 ) 2 = C m + 1 2 p(1,m)=\cfrac {m(m+1)}2=C_{m+1}^2 p(1,m)=2m(m+1)=Cm+12,有 p ( 2 , m ) = C m 2 + 2 C m − 1 2 + ⋯ + ( m − 1 ) C 2 2 = ( C m 2 + C m − 1 2 + ⋯ + C 2 2 ) + ( C m − 1 2 + C m − 2 2 + ⋯ + C 2 2 ) + ⋯ C 2 2 = C m + 1 3 + C m 3 + ⋯ + C 3 3 = C m + 2 4 . \begin{split} p(2,m)&=C_{m}^2+2C_{m-1}^2+\cdots+(m-1)C_{2}^2\\ &=(C_{m}^2+C_{m-1}^2+\cdots+C_{2}^2)+(C_{m-1}^2+C_{m-2}^2+\cdots+C_{2}^2)+\cdots C_{2}^2\\ &=C_{m+1}^3+C_{m}^3+\cdots+C_{3}^3\\ &=C_{m+2}^4 \end{split}. p(2,m)=Cm2+2Cm−12+⋯+(m−1)C22=(Cm2+Cm−12+⋯+C22)+(Cm−12+Cm−22+⋯+C22)+⋯C22=Cm+13+Cm3+⋯+C33=Cm+24. 类似的,可得关系式 p ( n , m ) = C n + m 2 n p(n,m)=C_{n+m}^{2n} p(n,m)=Cn+m2n,故最终答案为: C n + m 2 n ∏ i = 1 n A i + ∑ j = 1 n − 1 ( C j + m 2 j − C j + m − 1 2 j ) ∏ i = 1 j A i . C_{n+m}^{2n}\prod_{i=1}^nA_i+\sum_{j=1}^{n-1}(C_{j+m}^{2j}-C_{j+m-1}^{2j})\prod_{i=1}^jA_i. Cn+m2ni=1∏nAi+j=1∑n−1(Cj+m2j−Cj+m−12j)i=1∏jAi. 不对 p p p 做优化的情况下时间复杂度为 O ( n 2 log m ) O(n^2\log m) O(n2logm),因此 p p p 的值还需迭代计算,最终复杂度为 O ( n log m ) O(n\log m) O(nlogm)。此外,在杨辉三角中我们也可以看到 p ( n , m ) 、 p ( n − 1 , m − 1 ) 、 p ( n − 1 , n − 1 ) p(n,m)、p(n-1,m-1)、p(n-1,n-1) p(n,m)、p(n−1,m−1)、p(n−1,n−1) 恰围成一个菱形,什么数形结合。
先睡觉