蓝桥杯 2022年国赛真题
Java 大学A组
先做做 CB。
试题 A: 火柴棒数字
本题总分: 5 5 5 分
【问题描述】
小蓝最近迷上了用火柴棒拼数字字符,方法如下图所示 : : :
他只能拼 0 0 0 至 9 9 9 这十种数字字符,其中每个数字字符需要的火柴棒的数目依次是 : : : 6 , 2 , 5 , 5 , 4 , 5 , 6 , 3 , 7 , 6 6,2,5,5,4,5,6,3,7,6 6,2,5,5,4,5,6,3,7,6。他不喜欢重复拼同一个数字字符,所以对于每个数字字符他最多拼十个。小蓝会把拼出来的数字字符组合在一起形成一个整数, 例如对于整数 345 345 345,需要的火柴棒的数目为 5 + 4 + 5 = 14 5 + 4 + 5 = 14 5+4+5=14 根。小蓝有 300 300 300 根火柴棒,他想知道自己能拼出的最大整数是多少?可以不使用完这 300 300 300 根火柴棒,可以有多余的火柴棒剩下。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个由大写字母组成的字符串,在提交答案时只填写这个字符串,填写多余的内容将无法得分。
9999999999777777777755555555554444444444333333333322222222221111111111
多重背包
将数字视作价值为 1 1 1 且各有 10 10 10 个的物品,需要的火柴棒视作其重量,这显然是个多重背包问题。
不采用滚动数组以便还原组合方案,在还原方案的时候优先输出尽可能多的,值较大的数字即可。
public class Test {
public static void main(String[] args) { new Test().run(); }
int N = 300, W[] = { 0,6,2,5,5,4,5,6,3,7,6 };
void run() {
int[][] dp = new int[11][N + 1];
for (int i = 1; i <= 10; ++i)
for (int k = 0; k <= 10; ++k)
for (int j = k * W[i]; j <= 300; ++j)
dp[i][j] = max(dp[i][j], dp[i - 1][j - k * W[i]] + k);
for (int i = 10, j = 300, k = 0; i > 0; --i, k = 0) {
for (int g = 1; g <= 10 && j - g * W[i] >= 0; ++g)
if (dp[i][j] <= dp[i - 1][j - g * W[i]] + g) k = g;
for (j -= k * W[i]; k > 0; --k) System.out.print(i - 1);
}
}
int max(int arg1, int arg2) { return arg1 > arg2 ? arg1 : arg2; }
}
试题 B: 小蓝与钥匙
本题总分: 5 5 5 分
【问题描述】
小蓝是幼儿园的老师,他的班上有 28 28 28 个孩子,今天他和孩子们一起进行了一个游戏。
小蓝所在的学校是寄宿制学校, 28 28 28 个孩子分别有一个自己的房间,每个房间对应一把钥匙,每把钥匙只能打开自己的门。现在小蓝让这 28 28 28 个孩子分别将自己宿舍的钥匙上交,再把这 28 28 28 把钥匙随机打乱分给每个孩子一把钥匙,有 28 ! = 28 × 27 × ⋯ × 1 28! = 28×27×\cdots×1 28!=28×27×⋯×1 种分配方案。小蓝想知道这些方案中,有多少种方案恰有一半的孩子被分到自己房间的钥匙(即有 14 14 14 个孩子分到的是自己房间的钥匙,有 14 14 14 个孩子分到的不是自己房间的钥匙)。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
1286583532342313400
组合数学
28 28 28 个孩子中,任选 14 14 14 个孩子拿到自己房间钥匙的组合数乘以第 14 14 14 个错位排列数,即 C 28 14 × D 14 C_{28}^{14} \times D_{14} C2814×D14 就是我们所要提交的答案。
public class Test {
public static void main(String[] args) { new Test().run(); }
void run() { System.out.println(C(28, 14) * D(14)); }
long C(int n, int m) {
if (m > n || n < 0) return 0;
if (n == m) return 1;
return C(n - 1, m) + C(n - 1, m - 1);
}
long D(int n) {
if (n == 1) return 0;
if (n == 2) return 1;
return (n - 1) * (D(n - 1) + D(n - 2));
}
}
试题 C: 内存空间
时间限制: 3.0 s 3.0\mathrm s 3.0s 内存限制: 512.0 M B 512.0\mathrm{MB} 512.0MB 本题总分: 10 10 10 分
【问题描述】
小蓝最近总喜欢计算自己的代码中定义的变量占用了多少内存空间。
为了简化问题,变量的类型只有以下三种:
i
n
t
:
\mathrm{int}:
int:整型变量,一个
i
n
t
\mathrm{int}
int 型变量占用
4
B
y
t
e
4\ \mathrm{Byte}
4 Byte 的内存空间。
l
o
n
g
:
\mathrm{long}:
long:长整型变量,一个
l
o
n
g
\mathrm{long}
long 型变量占用
8
B
y
t
e
8\ \mathrm{Byte}
8 Byte 的内存空间。
S
t
r
i
n
g
:
\mathrm{String}:
String:字符串变量,占用空间和字符串长度有关,设字符串长度为
L
L
L,则字符串占用
L
B
y
t
e
L\ \mathrm{Byte}
L Byte 的内存空间,如果字符串长度为
0
0
0 则占用
0
B
y
t
e
0\ \mathrm{Byte}
0 Byte 的内存空间。
定义变量的语句只有两种形式,第一种形式为 : : :
t y p e v a r 1 = v a l u e 1 , v a r 2 = v a l u e 2 ⋯ ; \mathrm{type\ var1=value1},\ \mathrm{var2=value2}\cdots; type var1=value1, var2=value2⋯;
定义了若干个 t y p e \mathrm{type} type 类型变量 v a r 1 \mathrm{var1} var1、 v a r 2 \mathrm{var2} var2、 ⋯ \cdots ⋯,并且用 v a l u e 1 \mathrm{value1} value1、 v a l u e 2 ⋯ \mathrm{value2}\cdots value2⋯ 初始化,
多个变量之间用 ’ , ’ ’,’ ’,’ 分隔,语句以 ’ ; ’ ’;’ ’;’ 结尾, t y p e \rm type type 可能是 i n t \rm int int、 l o n g \rm long long 或 S t r i n g \rm String String。例如 i n t a = 1 , b = 5 , c = 6 ; \rm int a=1,\ b=5,\ c=6; inta=1, b=5, c=6; 占用空间为 12 B y t e 12\ \rm Byte 12 Byte; l o n g a = 1 , b = 5 ; \rm long\ a=1,\ b=5; long a=1, b=5; 占用空间为 16 B y t e 16\ \rm Byte 16 Byte; S t r i n g s 1 = ”” , s 2 = ” h e l l o ” , s 3 = ” w o r l d ” ; \rm String \ s1=””,\ s2=”hello”,\ s3=”world”; String s1=””, s2=”hello”, s3=”world”; 占用空间为 10 B y t e 10\ \rm Byte 10 Byte。
第二种形式为 : : :
t y p e [ ] a r r 1 = n e w t y p e [ s i z e 1 ] , a r r 2 = n e w t y p e [ s i z e 2 ] ⋯ ; \rm type[\:]\ arr1=new\ type[size1],arr2=new\ type[size2]\cdots; type[] arr1=new type[size1],arr2=new type[size2]⋯;
定义了若干 t y p e \rm type type 类型的一维数组变量 a r r 1 \rm arr1 arr1、 a r r 2 ⋯ \rm arr2\cdots arr2⋯,且数组的大小为 s i z e 1 \rm size1 size1、 s i z e 2 ⋯ \rm size2\cdots size2⋯,多个变量之间用 ’ , ’ ’,’ ’,’ 进行分隔,语句以 ’ ; ’ ’;’ ’;’ 结尾, t y p e \rm type type 只可能是 i n t \rm int int 或 l o n g \rm long long。例如 i n t [ ] a 1 = n e w i n t [ 10 ] ; \rm int[\:]\ a1=new\ int[10]; int[] a1=new int[10]; 占用的内存空间为 40 B y t e 40\ \rm Byte 40 Byte; l o n g [ ] a 1 = n e w l o n g [ 10 ] , a 2 = n e w l o n g [ 10 ] ; \rm long[\:]\ a1=new\ long[10],\ a2=new\ long[10]; long[] a1=new long[10], a2=new long[10]; 占用的内存空间为 160 B y t e 160\ \rm Byte 160 Byte。
已知小蓝有 T T T 条定义变量的语句,请你帮他统计下一共占用了多少内存空间。结果的表示方式为 : : : a G B b M B c K B d B a\mathrm{GB}b\mathrm{MB}c\mathrm{KB}d\mathrm B aGBbMBcKBdB,其中 a a a、 b b b、 c c c、 d d d 为统计的结果, G B \rm GB GB、 M B \rm MB MB、 K B \rm KB KB、 B \rm B B 为单位。优先用大的单位来表示, 1 G B = 1024 M B \rm 1GB=1024MB 1GB=1024MB, 1 M B = 1024 K B \rm 1MB=1024KB 1MB=1024KB, 1 K B = 1024 B \rm 1KB=1024B 1KB=1024B,其中 B B B 表示 B y t e \rm Byte Byte。如果 a a a、 b b b、 c c c、 d d d 中的某几个数字为 0 0 0,那么不必输出这几个数字及其单位。题目保证一行中只有一句定义变量的语句,且每条语句都满足题干中描述的定义格式,所有的变量名都是合法的且均不重复。题目中的数据很规整,和上述给出的例子类似,除了类型后面有一个空格,以及定义数组时 n e w \rm new new 后面的一个空格之外,不会出现多余的空格。
【输入格式】
输入的第一行包含一个整数 T T T ,表示有 T T T 句变量定义的语句。
接下来 T T T 行,每行包含一句变量定义语句。
【输出格式】
输出一行包含一个字符串,表示所有语句所占用空间的总大小。
【样例输入 1】
1
long[] nums=new long[131072];
【样例输出 1】
1MB
【样例输入 2】
4
int a=0,b=0;
long x=0,y=0;
String s1="hello",s2="world";
long[] arr1=new long[100000],arr2=new long[100000];
【样例输出 2】
1MB538KB546B
【样例说明】
样例
1
1
1,占用的空间为
131072
×
8
=
1048576
B
131072×8 = 1048576\ \mathrm B
131072×8=1048576 B,换算过后正好是
1
M
B
1\ \rm MB
1 MB,其 它三个单位
G
B
\rm GB
GB、
K
B
\rm KB
KB、
B
\rm B
B 前面的数字都为
0
0
0 ,所以不用输出。
样例
2
2
2,占用的空间为
4
×
2
+
8
×
2
+
10
+
8
×
100000
×
2
B
4×2 + 8×2 + 10 + 8×100000×2 \mathrm\ B
4×2+8×2+10+8×100000×2 B,换算后是
1
M
B
538
K
B
546
B
1\mathrm{MB}538\mathrm{KB}546\mathrm B
1MB538KB546B。
【评测用例规模与约定】
对于所有评测用例, 1 ≤ T ≤ 10 1 ≤ T ≤ 10 1≤T≤10,每条变量定义语句的长度不会超过 1000 1000 1000。所有的变量名称长度不会超过 10 10 10,且都由小写字母和数字组成。对于整型变 量,初始化的值均是在其表示范围内的十进制整数,初始化的值不会是变量。 对于 S t r i n g \rm String String 类型的变量,初始化的内容长度不会超过 50 50 50,且内容仅包含小写字母和数字,初始化的值不会是变量。对于数组类型变量,数组的长度为一个 整数,范围为 : : : [ 0 , 2 30 ] [0,2^{30}] [0,230],数组的长度不会是变量。 T T T 条语句定义的变量所占的内存空间总大小不会超过 1 G B 1\ \rm GB 1 GB,且大于 0 B 0\ \rm B 0 B。
挨喷题。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class Main {
public static void main(String[] args) { new Main().run(); }
String[] unit = { "", "K", "M", "G" };
void run() {
long count = 0;
try (BufferedReader in = new BufferedReader(new InputStreamReader(System.in))) {
for (int T = Integer.parseInt(in.readLine()); T-- > 0;) {
String line = in.readLine();
if (line.startsWith("String")) {
for (int flag = 0, i = 0, j = 0; i < line.length(); ++i) {
if (line.charAt(i) == '"') {
count += flag * (i - j - 1);
flag ^= 1;
j = i;
}
}
} else {
long buffer = 0;
if (line.charAt(3) == '[' || line.charAt(4) == '[')
for (int i = 6, j = 0; i < line.length(); ++i) {
if (line.charAt(i) == '[') j = i;
else if (line.charAt(i) == ']')
buffer += Integer.parseInt(line.substring(j + 1, i));
}
else buffer = line.split(",").length;
count += buffer << (line.startsWith("int") ? 2 : 3);
}
}
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 3; i >= 0; --i)
if (count >> (i * 10) > 0) {
System.out.print((count >> (i * 10)) + unit[i] + 'B');
count &= (1 << (i * 10)) - 1;
}
}
}
试题 D: 斐波那契数组
时间限制: 3.0 s 3.0\mathrm s 3.0s 内存限制: 512.0 M B 512.0\mathrm{MB} 512.0MB 本题总分: 10 10 10 分
【问题描述】
如果数组 A = ( a 0 , a 1 , ⋯ , a n − 1 ) A = (a_0,a_1,\cdots ,a_{n−1}) A=(a0,a1,⋯,an−1) 满足以下条件,就说它是一个斐波那契数组 : : :
1.
1.
1.
n
≥
2
n≥2
n≥2;
2.
2.
2.
a
0
=
a
1
a_0 = a_1
a0=a1;
3.
3.
3. 对于所有的
i
(
i
≥
2
)
i(i≥2)
i(i≥2),都满足
a
i
=
a
i
−
1
+
a
i
−
2
a_i = a_{i−1} + a_{i−2}
ai=ai−1+ai−2。
现在,给出一个数组 A A A ,你可以执行任意次修改,每次修改将数组中的某个位置的元素修改为一个大于 0 0 0 的整数。请问最少修改几个元素之后,数组 A A A 会变成一个斐波那契数组。
【输入格式】
输入的第一行包含一个整数 n n n,表示数组 A A A 中的元素个数。
第二行包含 n n n 个整数 a 0 , a 1 , ⋯ , a n − 1 a_0,a_1, \cdots,a_{n−1} a0,a1,⋯,an−1,相邻两个整数之间用一个空格分隔。
【输出格式】
输出一行包含一个整数表示最少需要修改数组 A A A 中的几个元素之后,数组 A A A 可以变为一个斐波那契数组。
【样例输入】
5
1 2 2 4 8
【样例输出】
3
【样例说明】
将原数组修改为
(
1
,
1
,
2
,
3
,
5
)
(1,1,2,3,5)
(1,1,2,3,5),最少修改三个元素变成了一个斐波那契数组。
【评测用例规模与约定】
对于所有评测用例, 2 ≤ n ≤ 1 0 5 , 1 ≤ a i ≤ 1 0 6 2≤n≤10^5 ,1≤a_i ≤10^6 2≤n≤105,1≤ai≤106。
首先, F 31 > 1 e 6 F_{31} > 1e6 F31>1e6,而 1 ≤ a i ≤ 1 0 6 1≤a_i ≤10^6 1≤ai≤106,于是无论 a 0 , a 1 a_0,a_1 a0,a1 取哪个正整数,从 A A A 的第 30 30 30 项开始,所有的元素都需要修改,
同时,令 G G G 为 G 1 = G 2 = g G_1 =G_2 =g G1=G2=g 的 “广义斐波那契数列”(这个名词其实已经被定义了),观察 F F F 与 G G G 各项 : : :
G
1
=
g
F
1
G_1 = gF_1
G1=gF1
G
2
=
g
F
2
G_2 = gF_2
G2=gF2
G
3
=
g
F
1
+
g
F
2
=
g
(
F
1
+
F
2
)
=
g
F
3
G_3 = gF_1 + gF_2 = g(F_1 + F_2) = gF_3
G3=gF1+gF2=g(F1+F2)=gF3
⋮
\quad\ \ \ \vdots
⋮
G
n
=
g
(
F
n
−
1
+
F
n
−
2
)
=
g
F
n
G_n = g(F_{n-1} + F_{n-2}) = gF_n
Gn=g(Fn−1+Fn−2)=gFn
于是我们只需统计 A A A 中,与 F F F 比值出现频率最高的项集,然后将其的补集替换为对应的 “广义斐波那契数列” 就行了。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.io.IOException;
import java.util.TreeMap;
import java.util.Map;
public class Main {
public static void main(String[] args) { new Main().run(); }
double[] fib = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040 };
void run() {
Map<Double, Integer> map = new TreeMap();
int n = nextInt(), m = 0, a, ans = n;
if (n > 30) n = 30;
for (int i = 0; i < n; ++i) {
a = nextInt();
map.put(a / fib[i], map.getOrDefault(a / fib[i], 0) + 1);
}
for (Map.Entry<Double, Integer> entry : map.entrySet())
m = Math.max(m, entry.getValue());
System.out.print(ans - m);
}
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
int nextInt() {
try {
in.nextToken();
} catch (IOException e) {
e.printStackTrace();
}
return (int)in.nval;
}
}
试题 E: 交通信号
时间限制: 3.0 s 3.0\mathrm s 3.0s 内存限制: 512.0 M B 512.0\mathrm{MB} 512.0MB 本题总分: 15 15 15 分
【问题描述】
L Q \rm LQ LQ 市的交通系统可以看成由 n n n 个结点和 m m m 条有向边组成的有向图。在每条边上有一个信号灯,会不断按绿黄红黄绿黄红黄… 的顺序循环 (初始时刚好变到绿灯)。当信号灯为绿灯时允许正向通行,红灯时允许反向通行,黄灯时不允许通行。每条边上的信号灯的三种颜色的持续时长都互相独立,其中黄灯的持续时长等同于走完路径的耗时。当走到一条边上时,需要观察边上的信号灯,如果允许通行则可以通过此边,在通行过程中不再受信号灯的影响;否则需要等待,直到允许通行。 请问从结点 s s s 到结点 t t t 所需的最短时间是多少,如果 s s s 无法到达 t t t 则输出 − 1 −1 −1。
【输入格式】
输入的第一行包含四个整数 n , m , s , t n,m,s,t n,m,s,t,相邻两个整数之间用一个空格分隔。
接下来 m m m 行,每行包含五个整数 u i , v i , g i , r i , d i u_i,v_i,g_i,r_i,d_i ui,vi,gi,ri,di,相邻两个整数之间用一个空格分隔,分别表示一条边的起点,终点,绿灯、红灯的持续时长和距离(黄灯的持续时长)。
【输出格式】
输出一行包含一个整数表示从结点 s s s 到达 t t t 所需的最短时间。
【样例输入】
4 4 1 4
1 2 1 2 6
4 2 1 1 5
1 3 1 1 1
3 4 1 99 1
【样例输出】
11
【评测用例规模与约定】
对于
40
%
40\%
40% 的评测用例,
n
≤
500
n≤500
n≤500,
1
≤
g
i
,
r
i
,
d
i
≤
100
1≤g_i,r_i,d_i ≤100
1≤gi,ri,di≤100;
对于
70
%
70\%
70% 的评测用例,
n
≤
5000
n≤5000
n≤5000;
对于所有评测用例,
1
≤
n
≤
100000
,
1
≤
m
≤
200000
,
1
≤
s
,
t
≤
n
,
1
≤
u
i
,
v
i
≤
n
,
1
≤
g
i
,
r
i
,
d
i
≤
1
0
9
1 ≤ n ≤ 100000,1 ≤ m ≤ 200000,1 ≤ s,t ≤ n,1≤u_i,v_i ≤n,1≤g_i,r_i,d_i ≤10^9
1≤n≤100000,1≤m≤200000,1≤s,t≤n,1≤ui,vi≤n,1≤gi,ri,di≤109。
// 毒瘤
试题 F: 数组个数
时间限制: 3.0 s 3.0\mathrm s 3.0s 内存限制: 512.0 M B 512.0\mathrm{MB} 512.0MB 本题总分: 15 15 15 分
【问题描述】
小蓝有一个长度为 n n n 的数组 B = ( b 0 , b 1 , ⋯ , b n − 1 ) B = (b_0,b_1,\cdots,b_{n−1}) B=(b0,b1,⋯,bn−1),数组 B B B 是由另一个长度为 n n n 的环形数组 A = ( a 0 , a 1 , ⋯ , a n − 1 ) A = (a_0,a_1,\cdots,a_{n−1}) A=(a0,a1,⋯,an−1) 经过一次相邻最大化操作得到的,其中 a i a_i ai 与 a i + 1 a_{i+1} ai+1 相邻, a 0 a_0 a0 与 a n − 1 a_{n−1} an−1 相邻。
形式化描述为 : : : b i = { max ( a n − 1 , a 0 , a 1 ) , ( i = 0 ) ; max ( a i − 1 , a i , a i + 1 ) , ( 0 < i < n − 1 ) ; max ( a n − 2 , a n − 1 , a 0 ) , ( i = n − 1 ) . b_i=\begin{cases}\max(a_{n-1},a_0,a_1),&(i=0);\\\max(a_{i-1},a_i,a_{i+1}), & (0<i<n-1);\\\max(a_{n-2},a_{n-1},a_0), & (i=n-1).\end{cases} bi=⎩ ⎨ ⎧max(an−1,a0,a1),max(ai−1,ai,ai+1),max(an−2,an−1,a0),(i=0);(0<i<n−1);(i=n−1). 小蓝想知道,可能有多少个满足条件的数组 A A A,经过一次相邻最大化操作后能得到数组 B B B,注意 A A A 中的每个元素都要求为非负整数。
【输入格式】
输入的第一行包含一个整数 n n n,表示数组长度。
第二行包含 n n n 个整数 b 0 , b 1 , ⋯ , b n − 1 b_0,b_1,\cdots,b_{n−1} b0,b1,⋯,bn−1,相邻两个整数之间用一个空格分隔。
【输出格式】
输出一行包含一个整数表示答案,答案可能很大,请输出答案除以 1000000007 1000000007 1000000007 后的余数。
【样例输入】
5
8 6 1 8 8
【样例输出】
7
【样例说明】
可能的
A
A
A 数组有
7
7
7 个
:
:
:
(
6
,
0
,
0
,
1
,
8
)
(6,0,0,1,8)
(6,0,0,1,8)、
(
6
,
0
,
1
,
0
,
8
)
(6,0,1,0,8)
(6,0,1,0,8)、
(
6
,
0
,
1
,
1
,
8
)
(6,0,1,1,8)
(6,0,1,1,8)、
(
6
,
1
,
0
,
0
,
8
)
(6,1,0,0,8)
(6,1,0,0,8)、
(
6
,
1
,
0
,
1
,
8
)
(6,1,0,1,8)
(6,1,0,1,8)、
(
6
,
1
,
1
,
0
,
8
)
(6,1,1,0,8)
(6,1,1,0,8)、
(
6
,
1
,
1
,
1
,
8
)
(6,1,1,1,8)
(6,1,1,1,8)。
【评测用例规模与约定】
对于
30
%
30\%
30% 的评测用例,
3
≤
n
≤
10
3≤n≤10
3≤n≤10;
对于
60
%
60\%
60% 的评测用例,
3
≤
n
≤
100
3≤n≤100
3≤n≤100;
对于所有评测用例,
3
≤
n
≤
1000
,
0
≤
b
i
≤
10
3≤n≤1000,0≤b_i ≤10
3≤n≤1000,0≤bi≤10。
动态规划
一定存在最小的索引 i i i,对某个序列 A A A 的任意索引 j j j 满足 a i ≥ a j a_i \geq a_j ai≥aj,显然当 A A A 进行一次相邻最大化操作后得到的序列 B B B 中, b i − 1 m o d n = b i = b i + 1 m o d n = a i b_{i -1\mod n} = b_{i} = b_{i +1\mod n} = a_i bi−1modn=bi=bi+1modn=ai。反之对于给定的序列 B B B,也一定存在最小的索引 i ′ i' i′,对任意索引 j ′ j' j′ 满足 a i ′ ≥ a j ′ a_{i'} \geq a_{j'} ai′≥aj′,在不考虑 b 0 = b n − 1 b_0 = b_{n-1} b0=bn−1 的情况下显然有 b i ′ − 1 m o d n < b i ′ b_{i'-1\mod n} < b_{i'} bi′−1modn<bi′,显然 b i ′ b_{i'} bi′ 不能由 a i ′ − 1 m o d n 、 a i ′ a_{i' - 1 \mod n}、a_{i'} ai′−1modn、ai′ 确定,这样会使 b i ′ − 1 m o d n = b i ′ b_{i'-1\mod n} = b_{i'} bi′−1modn=bi′,因此 a i ′ + 1 m o d n a_{i' + 1\mod n} ai′+1modn 与 b i ′ b_{i'} bi′ 相互唯一确定,我们可以根据这个性质将题目给定的序列 B B B 的环拆开。
然后定义 f i , j f_{i,j} fi,j 为长度为 i i i 的可以确定 B B B 长度为 i + j − 1 i + j - 1 i+j−1 的前缀的序列个数,我们将 B B B 从 i ′ ∼ i ′ + 1 i'\sim i' +1 i′∼i′+1 处断开,显然 f i ′ + 1 , 2 = 1 f_{i'+1,2} = 1 fi′+1,2=1,以 ( 8 , 6 , 1 , 8 , 8 ) (8,6,1,8,8) (8,6,1,8,8)为例,拆开环后为序列 { 8 , 8 , 6 , 1 , 8 } \{8,8,6,1,8\} {8,8,6,1,8},第一位只能填 8 8 8,可以确定长度为 1 + 2 − 1 1 + 2 - 1 1+2−1 的前缀 { 8 , 8 } \{8,8\} {8,8},因此 f i ′ , 2 = 1 f_{i',2} = 1 fi′,2=1。
因为 max ( b i ) = 10 \max(b_i) = 10 max(bi)=10,它的规模很小,所以我们可以对每一个 i i i 都枚举可能的 b i b_{i} bi 然后去累计它加入后能拼凑起 B B B 到某个长度的方案数即可,代码写的太大坨了就不用文字具体描述了,总之算法复杂度为 O ( N max ( b i ) ) O(N\max(b_i)) O(Nmax(bi))。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
public class Main {
public static void main(String[] args) { new Main().run(); }
int MOD = 1000000007;
int[] B = new int[2022];
int[][] dp = new int[2022][3];
void run() {
int n = nextInt(), m = 0;
for (int i = 0; i < n; ++i) {
B[i] = B[i + n] = nextInt();
if (B[i] > B[m]) m = i;
}
if (m == 0 && B[n - 1] == B[0]) {
for (int i = n - 2; i >= 0; --i)
if (B[i] != B[m]) {
m = i + 1;
break;
}
}
if (m == n - 1) m = 0;
else n += ++m;
dp[m][2] = 1;
for (int i = m + 1; i < n; ++i)
for (int k = 0; k <= 10; ++k) {
if (k < B[i - 1] && k < B[i] && k < B[i + 1]) {
dp[i][0] = (dp[i][0] + dp[i - 1][1]) % MOD;
dp[i][1] = (dp[i][1] + dp[i - 1][2]) % MOD;
} else if (k == B[i + 1] && k <= B[i - 1] && k <= B[i]) {
dp[i][2] = (dp[i][2] + dp[i - 1][2]) % MOD;
if (k == B[i - 1]) dp[i][2] = (dp[i][2] + dp[i - 1][0]) % MOD;
if (k == B[i]) dp[i][2] = (dp[i][2] + dp[i - 1][1]) % MOD;
} else if (k == B[i] && k <= B[i - 1] && k <= B[i + 1]) {
dp[i][1] = (dp[i][1] + dp[i - 1][1]) % MOD;
dp[i][1] = (dp[i][1] + dp[i - 1][2]) % MOD;
if (k == B[i - 1]) dp[i][1] = (dp[i][1] + dp[i - 1][0]) % MOD;
} else if (k == B[i - 1] && k <= B[i] && k <= B[i + 1]) {
dp[i][0] = (dp[i][0] + dp[i - 1][0]) % MOD;
dp[i][0] = (dp[i][0] + dp[i - 1][1]) % MOD;
dp[i][0] = (dp[i][0] + dp[i - 1][2]) % MOD;
}
}
System.out.println(dp[n - 1][0]);
}
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
int nextInt() {
try {
in.nextToken();
} catch (java.io.IOException e) {
}
return (int)in.nval;
}
}
试题 G: 六六大顺
时间限制: 3.0 s 3.0\mathrm s 3.0s 内存限制: 512.0 M B 512.0\mathrm{MB} 512.0MB 本题总分: 20 20 20 分
【问题描述】
六六大顺,本指农历六月初六。多用于祝福中年人士家庭幸福,工作顺利, 事业有成,身体健康。源自《左传》“君义,臣行,父慈,子孝,兄爱,弟敬, 此数者累谓六顺也。”
6 6 6 在我国自古以来是一个吉祥的数字,定义数列 A = ( a 1 , a 2 , ⋯ , a i , ⋯ ) A = (a_1,a_2,\cdots,a_i,\cdots) A=(a1,a2,⋯,ai,⋯),其中 a 1 = 6 , a 2 = 66 , ⋯ , a i = 10 ⋅ a i − 1 + 6 a_1 = 6, a_2 = 66, \cdots, a_i = 10\cdot a_{i−1} + 6 a1=6,a2=66,⋯,ai=10⋅ai−1+6。
定义一个数列 B = ( b 1 , b 2 , ⋯ , b i , ⋯ ) B = (b_1,b_2,\cdots,b_i,\cdots) B=(b1,b2,⋯,bi,⋯),其中 $b_1 = 6 × 6 , b 2 = 66 × 66 , ⋯ , b i = a i ⋅ a i 6×6, b_2 = 66×66, \cdots, b_i = a_i \cdot a_i 6×6,b2=66×66,⋯,bi=ai⋅ai。
现在小蓝想知道数列 B B B 的前 n n n 项的和是多少,你能帮帮小蓝吗?
【输入格式】
输入一行包含一个正整数 n n n。
【输出格式】
输出一行包含一个整数表示数列 B B B 前 n n n 项的和。
【样例输入】
3
【样例输出】
447948
【样例说明】
b
1
=
6
×
6
=
36
,
b
2
=
66
×
66
=
4356
,
b
3
=
666
×
666
=
443556
b_1 = 6×6 = 36,b_2 = 66×66 = 4356,b_3 = 666×666 = 443556
b1=6×6=36,b2=66×66=4356,b3=666×666=443556,所以前三项的和为
36
+
4356
+
443556
=
447948
36 + 4356 + 443556 = 447948
36+4356+443556=447948。
【评测用例规模与约定】
对于
20
%
20\%
20% 的评测用例,
1
≤
n
≤
100
1≤n≤100
1≤n≤100;
对于
50
%
50\%
50% 的评测用例,
1
≤
n
≤
100000
1≤n≤100000
1≤n≤100000;
对于所有评测用例,
1
≤
n
≤
10000000
1≤n≤10000000
1≤n≤10000000。
规律 A
有 b i = 444 ⋯ 444 ⏟ i个4 × 999 ⋯ 999 ⏟ i个9 = 4 ( 111 ⋯ 111 ⏟ i个1 × 1 000 ⋯ 000 ⏟ i个0 − 111 ⋯ 111 ⏟ i个1 ) b_i = \underbrace{444\cdots444}_{\text{i个4}}\times\underbrace{999\cdots999}_{\text{i个9}}=4(\underbrace{111\cdots111}_{\text{i个1}}\times1\underbrace{000\cdots000}_{\text{i个0}}-\underbrace{111\cdots111}_{\text{i个1}}) bi=i个4 444⋯444×i个9 999⋯999=4(i个1 111⋯111×1i个0 000⋯000−i个1 111⋯111),不考虑进位的情况下 ∑ i = 1 n 111 ⋯ 111 ⏟ i个1 000 ⋯ 000 ⏟ i个0 = 112233 ⏟ n-1个 ⋯ ⌈ n 2 ⌉ ⋯ 332211 ⏟ n-1个 0 \sum_{i=1}^n\underbrace{111\cdots111}_{\text{i个1}} \underbrace{000\cdots000}_{\text{i个0}} =\underbrace{112233}_{\text{n-1个}}\cdots \lceil\cfrac n2\rceil \cdots\underbrace{332211}_{\text{n-1个}}0 ∑i=1ni个1 111⋯111i个0 000⋯000=n-1个 112233⋯⌈2n⌉⋯n-1个 3322110,同理 ∑ i = 1 n 111 ⋯ 111 ⏟ i个1 = n ⋯ 321 \sum_{i=1}^n\underbrace{111\cdots111}_{\text{i个1}}=n\cdots321 ∑i=1ni个1 111⋯111=n⋯321,相减处理下进退位答案就出来了。
import java.io.PrintWriter;
import java.util.Scanner;
public class Main {
public static void main(String ...args) { new Main().run(); }
byte[] buffer = new byte[1 << 25];
void run() {
PrintWriter out = new PrintWriter(System.out);
int n = new Scanner(System.in).nextInt();
long carry = 0;
for (int i = 0; i < n; ++i) {
carry += ((i + 1l) / 2 - n + i << 2);
buffer[i] = (byte)(carry % 10);
carry /= 10;
if (buffer[i] < 0) {
buffer[i] += 10;
--carry;
}
}
for (int i = 0; i < n; ++i) {
carry += (n - i + 1) / 2 << 2;
buffer[n + i] = (byte)(carry % 10);
carry /= 10;
if (buffer[n + i] < 0) {
buffer[n + i] += 10;
--carry;
}
}
for (int i = 2 * n - 1; i >= 0; --i)
out.write(buffer[i] + '0');
out.flush();
}
}
规律 B
111 ⋯ 111 ⏟ n个1 × 111 ⋯ 111 ⏟ n个1 \underbrace{111\cdots111}_{\text{n个1}}\times\underbrace{111\cdots111}_{\text{n个1}} n个1 111⋯111×n个1 111⋯111 可以展开为 111 ⋯ 111 ⏟ n个1 × ( 1 000 ⋯ 0 ⏟ n-1个0 + 1 00 ⋯ 0 ⏟ n-2个0 + ⋯ + 1 ) \underbrace{111\cdots111}_{\text{n个1}}\times(1\underbrace{000\cdots0}_{\text{n-1个0}} +1\underbrace{00\cdots0}_{\text{n-2个0}}+\cdots+1) n个1 111⋯111×(1n-1个0 000⋯0+1n-2个0 00⋯0+⋯+1),不考虑进位的情况下,可列竖式: 111 ⋯ 111 ⏞ n个1 111 ⋯ 1110 ⋮ 111 ⋯ 111 ⏟ n个1 000 ⋯ 00 ⏟ n-1个0 12345 ⋯ n ⋯ 54321 \def\arraystretch{1} \begin{array}{r} \overbrace{111\cdots111}^{\text{n个1}}\\ 111\cdots1110 \\ \vdots\hspace{26pt}\\ \underbrace{111\hspace{0.5pt}\cdots111}_{\text{n个1}}\underbrace{000\hspace{0.5pt}\cdots00}_{\text{n-1个0}_{}} \\\hline 12345\cdots n\cdots54321 \end{array} 111⋯111 n个1111⋯1110⋮n个1 111⋯111n-1个0 000⋯0012345⋯n⋯54321. 设 c i = 111 ⋯ 111 ⏟ i个1 2 c_i = {\underbrace{111\cdots111}_{\text{i个1}}}^2 ci=i个1 111⋯1112,根据上式 ∑ i = 1 n c i \sum_{i=1}^n c_i ∑i=1nci 可列竖式: 1 121 12321 ⋮ 12345 ⋯ n ⋯ 54321 \def\arraystretch{1} \begin{array}{r} 1\\ 121\\ 12321\\ \vdots\hspace{11pt}\\ 12345\cdots n\cdots54321\\\hline \end{array} 112112321⋮12345⋯n⋯54321 可知 ∑ i = 1 n c i = ∑ j = 1 n ( j × ( n − j + 1 ) × 1 0 j − 1 ) + ∑ j = 1 n − 1 ∑ k = 1 j ( k × 1 0 2 ( n − j ) + k − 1 ) \sum_{i=1}^n c_i = \sum_{j=1}^n(j \times(n - j + 1)\times10^{j-1})+\sum_{j=1}^{n-1}\sum_{k=1}^{j}(k\times10^{2(n-j)+k-1}) ∑i=1nci=∑j=1n(j×(n−j+1)×10j−1)+∑j=1n−1∑k=1j(k×102(n−j)+k−1),以及 ∑ b i = 6 2 ∑ c i \sum b_i = 6^2\sum c_i ∑bi=62∑ci。
不过 n n n 的阶很高,我们将低 i i i 位拆成 i × ( n − i + 1 ) + ∑ j = 1 ⌊ i − 1 2 ⌋ ( j + 1 − i m o d 2 ) i\times(n-i+1)+\sum_{j=1}^{\lfloor\frac {i-1}2\rfloor}(j+1-i \mod 2) i×(n−i+1)+∑j=1⌊2i−1⌋(j+1−imod2) 计算,而不用上式,同时记录进位,不然会超时。
import java.io.PrintWriter;
import java.util.Scanner;
public class Main {
public static void main(String ...args) { new Main().run(); }
byte[] buffer = new byte[1 << 25];
long[] sum = new long[2];
void run() {
PrintWriter out = new PrintWriter(System.out);
int n = new Scanner(System.in).nextInt(), m = 0;
long carry = 0;
for (int i = 1; i <= n; ++i) {
carry += i * (n - i + 1l) * 36;
carry += sum[i & 1] * 36;
sum[i & 1] += i;
buffer[m++] = (byte)(carry % 10);
carry /= 10;
}
sum[n & 1] -= n;
for (int i = n - 1; i > 0; --i) {
carry += sum[i & 1] * 36;
sum[i & 1] -= i;
buffer[m++] = (byte)(carry % 10);
carry /= 10;
}
if (carry > 0) out.print(carry);
while (m-- > 0)
out.write(buffer[m] + '0');
out.flush();
}
}
规律 C
有 b i = 666 ⋯ 666 ⏟ i个6 × 666 ⋯ 666 ⏟ i个6 = 4 9 × 999 ⋯ 999 ⏟ i个9 2 = 4 9 ( 1 000 ⋯ 000 ⏟ i个0 − 1 ) 2 = 4 9 ( 1 000 ⋯ 000 ⏟ i个0 2 − 2 × 1 000 ⋯ 000 ⏟ i个0 + 1 ) b_i = \underbrace{666\cdots666}_{\text{i个6}}\times\underbrace{666\cdots666}_{\text{i个6}}=\cfrac 49\times{\underbrace{999\cdots999}_{\text{i个9}}}^2=\cfrac 49(1\underbrace{000\cdots000}_{\text{i个0}}-1)^2=\cfrac 49(1{\underbrace{000\cdots000}_{\text{i个0}}}^2-2\times1\underbrace{000\cdots000}_{\text{i个0}}+1) bi=i个6 666⋯666×i个6 666⋯666=94×i个9 999⋯9992=94(1i个0 000⋯000−1)2=94(1i个0 000⋯0002−2×1i个0 000⋯000+1)。
显然 ∑ i = 1 n b i = 4 9 ( ∑ i = 1 n 1 0 2 n − 2 ∑ i = 1 n 1 0 n + n ) = 4 9 ( 101010 ⋯ 100 ⏟ 2n+1位 − 222 ⋯ 20 ⏟ n+1位 + n ) \sum_{i=1}^nb_i = \cfrac 49(\sum_{i=1}^n10^{2n}-2\sum_{i=1}^n10^n+n)=\cfrac 49(\underbrace{101010\cdots100}_{\text{2n+1位}_{}}-\underbrace{222\cdots20}_{\text{n+1位}_{}}+n) ∑i=1nbi=94(∑i=1n102n−2∑i=1n10n+n)=94(2n+1位 101010⋯100−n+1位 222⋯20+n),用这三项乘以 4 4 4 来初始化高精度对象,然后除 9 9 9 就行。
import java.io.PrintWriter;
import java.util.Scanner;
public class Main {
public static void main(String ...args) { new Main().run(); }
int[] buffer = new int[20000001];
void run() {
PrintWriter out = new PrintWriter(System.out);
int n = new Scanner(System.in).nextInt();
buffer[0] = 4 * n % 10;
buffer[1] = 4 * n / 10;
for (int i = 1; i <= n; ++i) {
buffer[2 * i] += 4;
buffer[i] -= 8;
buffer[i + 1] += buffer[i] / 10;
buffer[i] %= 10;
if (buffer[i] < 0) {
buffer[i] += 10;
--buffer[i + 1];
}
}
for (int i = n + 1; buffer[i] < 0; ++i) {
buffer[i] += 10;
--buffer[i + 1];
}
for (int i = 2 * n - 1; i >= 0; --i) {
int num = 10 * buffer[i + 1] + buffer[i];
buffer[i] = num % 9;
out.print(num / 9);
}
out.flush();
}
}
当然这种题能找到的规律远远不止这点,但我不在乎。
试题 H: 选素数
时间限制: 3.0 s 3.0\mathrm s 3.0s 内存限制: 512.0 M B 512.0\mathrm{MB} 512.0MB 本题总分: 20 20 20 分
【问题描述】
小蓝有一个数 x x x,每次操作小蓝会选择一个小于 x x x 的素数 p p p,然后在 x x x 成为 p p p 的倍数前不断将 x x x 加 1 1 1,(如果 x x x 一开始就是 p p p 的倍数则 x x x 不变)。
小乔看到了小蓝进行了 2 2 2 次上述操作后得到的结果 n n n,他想知道 x x x 在一开始是多少。如果有多种可能,他想知道 x x x 一开始最小可以是多少,而如果不存在任何解,说明小乔看错了,此时请输出 − 1 −1 −1。
【输入格式】
输入一行包含一个整数 n n n,表示经过两次操作后 x x x 的值。
【输出格式】
输出一行包含一个整数表示 x x x 的初始值。如果有多个解,输出最小的。如果不存在解,请输出 − 1 −1 −1。
【样例输入】
22
【样例输出】
8
【评测用例规模与约定】
对于
60
%
60\%
60% 的评测用例,
1
≤
n
≤
5000
1≤n≤5000
1≤n≤5000;
对于所有评测用例,
1
≤
n
≤
1
0
6
1≤n≤10^6
1≤n≤106。
线性筛
若 n n n 是合数,则有 x x x 可能的最大值 x max = n x_{\max} = n xmax=n,最小值 x min = n − p + 1 x_{\min} = n - p + 1 xmin=n−p+1, p p p 为 n n n 的最大质因数,这是因为对于 n n n 的任意质因数 p ′ p' p′, x x x 选择任何不大于 n ( p ′ − 1 ) p ′ \cfrac {n(p'-1)}{p'} p′n(p′−1) 的初值,都会使小蓝的操作到 n ( p ′ − k ) p ′ , 1 ≤ k < p ′ \cfrac {n(p'-k)}{p'}, 1\leq k<p' p′n(p′−k),1≤k<p′ 就停止,而非 n n n,因此 x min = n − p + 1 x_{\min} = n - p + 1 xmin=n−p+1。
又设 n n n 的任意质因数为 p p p,最大质因数为 f n f_n fn,有 f n = max ( f n / p , p ) f_n = \max(f_{n/p}, p) fn=max(fn/p,p),这个用算术基本定理和分治的思想琢磨一下就行了,不想解释。
import java.util.Scanner;
public class Main {
public static void main(String ...args) { new Main().run(); }
int[] primes = new int[78498];
int[] f = new int[1000001];
void run() {
int n = new Scanner(System.in).nextInt();
int m = 0, ans = n;
for (int i = 2; i <= n; ++i) {
if (f[i] == 0) {
primes[m++] = i;
f[i] = i;
}
for (int j = 0; j < m; ++j) {
if (i * primes[j] > n) break;
f[i * primes[j]] = Math.max(f[i], primes[j]);
if (i % primes[j] == 0) break;
}
}
if (n == 1 || f[n] == n) System.out.print("-1");
else {
for (int i = n - f[n] + 1; i <= n; ++i)
if (i != f[i]) ans = Math.min(ans, i - f[i] + 1);
System.out.print(ans);
}
}
}
试题 I: 图书借阅
时间限制: 10.0 s 10.0\mathrm s 10.0s 内存限制: 1.0 G B 1.0\mathrm{GB} 1.0GB 本题总分: 25 25 25 分
【问题描述】
小蓝是一所图书馆的管理员,图书馆中目前有 n n n 种书,第 i i i 种书有 a i a_i ai 本。
小蓝目前有 m m m 条未来若干天中用户的预约借阅记录,每个借阅记录由 b i , l i , r i b_i,l_i,r_i bi,li,ri 组成,表示在 l i l_i li 日要借用一本书 b i b_i bi, r i r_i ri 日归还, r i r_i ri 日结束后图书馆才可以将这本书重新借出。
小蓝分析了一下预约借阅记录,发现现有的书不一定能满足所有人的预约请求,于是小蓝打算额外购买一些书加入到图书馆。小蓝的预算有限,请问如果额外添加不超过 x x x 本书,最多有多少条预约记录能得到满足? 小蓝可以选取一部分记录使其满足,不一定需要按借阅或预定的时间顺序满足。
【输入格式】
输入的第一行包含三个整数 n , m , x n,m,x n,m,x,相邻两个整数之间用一个空格分隔。
第二行包含 n n n 个整数 a 1 , a 2 , ⋯ , a n a_1,a_2,\cdots,a_n a1,a2,⋯,an,相邻两个整数之间用一个空格分隔,表示目前拥有的每种书的本数。
接下来 m m m 行,每行包含 3 3 3 个整数 b i , l i , r i b_i,l_i,r_i bi,li,ri,相邻两个整数之间用一个空格分隔,表示一条预约借阅记录。
【输出格式】
输出一行包含一个整数表示给定条件下最多能满足预约借阅的记录数。
【样例输入】
3 11 3
1 0 2
1 2 4
1 1 2
1 4 5
1 3 5
1 1 3
2 1 1
2 2 2
2 3 3
2 1 2
2 3 4
3 1 5
【样例输出】
10
【评测用例规模与约定】
对于
10
%
10\%
10% 的评测用例,
n
,
m
≤
10
,
l
i
≤
r
i
≤
10
n,m≤10,l_i ≤r_i ≤10
n,m≤10,li≤ri≤10;
对于
50
%
50\%
50% 的评测用例,
n
,
m
≤
2000
,
l
i
≤
r
i
≤
5000
n,m≤2000,l_i ≤r_i ≤5000
n,m≤2000,li≤ri≤5000;
对于所有评测用例,
1
≤
n
≤
100000
,
1
≤
x
≤
m
≤
200000
,
1
≤
b
i
≤
n
,
1
≤
l
i
≤
r
i
≤
1
0
6
,
0
≤
a
i
≤
1
0
5
1 ≤ n ≤ 100000 ,1 ≤ x ≤ m ≤ 200000,1 ≤ b_i ≤ n,1≤l_i ≤r_i ≤10^6,0≤a_i ≤10^5
1≤n≤100000,1≤x≤m≤200000,1≤bi≤n,1≤li≤ri≤106,0≤ai≤105。
试题 J: 括号序列树
时间限制: 5.0 s 5.0\mathrm s 5.0s 内存限制: 512.0 M B 512.0\mathrm{MB} 512.0MB 本题总分: 25 25 25 分
【问题描述】
有一棵二叉树,根结点上有一个空字符串,每个点的左儿子上的字符串为其父亲结点的字符串尾部额外加一个左括号,右儿子则是在尾部加一个右括号。树中的每个叶子结点上的字符串都分别和每个由 n n n 对括号组成的合法括号序列一一对应。
给定 n n n,求此时这棵树的最大匹配所含的边数。
【输入格式】
输入一行包含一个整数 n n n。
【输出格式】
输出一行包含一个整数表示满足条件的序列的数量,答案可能很大,请输出答案除以 998244353 998244353 998244353 的余数。
【样例输入】
9
【样例输出】
10350
【评测用例规模与约定】
对于
20
%
20\%
20% 的评测用例,
n
≤
10
n≤10
n≤10;
对于
40
%
40\%
40% 的评测用例,
n
≤
300
n≤300
n≤300;
对于
60
%
60\%
60% 的评测用例,
n
≤
5000
n≤5000
n≤5000;
对于
85
%
85\%
85% 的评测用例,
n
≤
1
0
5
n≤10^5
n≤105;
对于所有评测用例,
1
≤
n
≤
1
0
6
1≤n≤10^6
1≤n≤106。
组合数学
题面很烂,题意可以理解成将高
2
n
+
1
2n+1
2n+1 的满二叉树,将非法叶节点枝剪掉后,最大匹配为多少。例如当
n
=
2
n=2
n=2 时有枝剪后的二叉树:
它的最大匹配显然为
3
3
3。
于是衍生出两个问题:对于任意
n
n
n,其树形态若何;对于相应的二叉树,它的最大匹配与
n
n
n 之间的代数关系怎么推导。
先睡觉。