蓝桥杯 2021年省赛真题 (Java 大学A组 )

  • #A 相乘
    • 朴素解法
    • 同余方程
  • #B 直线
    • 直线方程集合
    • 分式消除误差
    • 平面几何
  • #C 货物摆放
    • 暴力搜索
    • 缩放质因子
  • #D 路径
    • 搜索
    • 单源最短路径
  • #E 回路计数
    • 记忆化搜索
  • #F 最少砝码
    • 变种三进制
  • #G 左孩子右兄弟
    • 树形 DP
  • #H 异或数列
    • 博弈论
  • #I 双向排序
    • 去冗操作
    • 填数游戏
    • Chtholly Tree
  • #J 分果果
    • 动态规划

Placeholder


#A 相乘

本题总分:555 分


问题描述

  小蓝发现,他将 111 至 100000000710000000071000000007 之间的不同的数与 202120212021 相乘后再求除以 100000000710000000071000000007 的余数,会得到不同的数。
  小蓝想知道,能不能在 111 至 100000000710000000071000000007 之间找到一个数,与 202120212021 相乘后再除以 100000000710000000071000000007 后的余数为 999999999999999999999999999。如果存在,请在答案中提交这个数;
  如果不存在,请在答案中提交 000。


答案提交

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


17812964


朴素解法


  朴素的去枚举 [1,1000000007][1,1000000007][1,1000000007] 中的每一个数,看似不明智,但实际上,

  对于现代的 CPU\mathrm{CPU}CPU 来说,就是洒洒水。

  就算你的 CPU\mathrm{CPU}CPU 主频低至 2.0Ghz2.0\mathrm{Ghz}2.0Ghz,那也是每秒钟二十亿次的计算速度。

  不要小瞧了现代计算机啊,混蛋。

public class Test {public static void main(String[] args) { new Test().run(); }int N = 1000000007, M = 999999999;void run() {for (int i = 1; i <= N; i++)if (i * 2021L % N == M) System.out.println(i);}
}

余数定义


  余数的定义是,

  给定两个整数 aaa、bbb,其中 b≠0b \ne 0b​=0,那么一定存在两个唯一的整数 qqq、rrr,使得a=qb+r,0≤r<∣b∣a=qb+r,0 \leq r < |b|a=qb+r,0≤r<∣b∣

  而在这道题中,我们最后要找的,可能存在的这个数字可表示为,

  2021⋅a′=1000000007⋅q+9999999992021 \cdot a' = 1000000007 \cdot q + 9999999992021⋅a′=1000000007⋅q+999999999,

  显然 qqq 不会超过 202120212021,

  枚举的变量选择为 qqq 的话,就能大大的减少枚举范围。

public class Test {public static void main(String[] args) { new Test().run(); }long N = 1000000007, M = 999999999;void run() {for (int i = 1; i < 2021; i++)if ((i * N + M) % 2021 == 0)System.out.println((i * N + M) / 2021);}
}

同余方程


扩展欧几里得算法


  依题意,有同余线性方程:

  a×x≡b(modn)a × x \equiv b \pmod{n}a×x≡b(modn),gcd⁡(a,n)∣b\gcd(a,n) \mid bgcd(a,n)∣b

  将 202120212021 代入 aaa,100000000710000000071000000007 代入 nnn,gcd⁡(a,n)=1\gcd(a,n)=1gcd(a,n)=1,方程有无穷解。


  稍微解释一下,

  a×x≡b(modn)a × x \equiv b \pmod{n}a×x≡b(modn) 可改写为 a×x+n×y=ba × x + n × y = ba×x+n×y=b,

  用扩展欧几里得算法求出一组数 x0,y0x_{0}, y_{0}x0​,y0​,使得 a×x0+n×y0=gcd⁡(a,n)a × x_{0} + n × y_{0} = \gcd(a,n)a×x0​+n×y0​=gcd(a,n),

  则 x=b×x0gcd⁡(a,n)x = \cfrac{b × x_{0}}{\gcd(a,n)}x=gcd(a,n)b×x0​​ 是原方程的一个解。

  通解为 b×x0gcd⁡(a,n)modn‾(modn)\overline{\cfrac{b × x_{0}}{\gcd(a,n)} \bmod n} \pmod{n}gcd(a,n)b×x0​​modn​(modn),

  人话一点就是模 nnn 与 xxx 同余的同余类。

def exgcd(a, b):if b == 0:return (1, 0, a)(x, y, d) = exgcd(b, a % b)return (y, x - a // b * y, d);(x, y, d) = exgcd(2021, 1000000007)
print((x * 999999999 // d) % (1000000007 // d))

  毕竟是结果填空题,

  就用 Python\mathrm{Python}Python 写了,

  下面再放个 Java\mathrm{Java}Java 的吧。


费马小定理


  对 aaa, a∈Za \in \mathbb{Z}a∈Z,若 ppp 为质数,gcd⁡(a,p)=1\gcd (a,p) = 1gcd(a,p)=1,有

  ap−1≡1(modp)a^{p-1} \equiv 1 \pmod pap−1≡1(modp)

  容易整理出方程,

  ax≡ap−1(modp)x≡ap−2(modp)bx≡bap−2≡b(modp)\begin{aligned}ax & \equiv a^{p-1} &\pmod p\\x & \equiv a^{p-2} &\pmod p\\bx & \equiv ba^{p-2} \equiv b &\pmod p\end{aligned}axxbx​≡ap−1≡ap−2≡bap−2≡b​(modp)(modp)(modp)​

public class Test {public static void main(String[] args) { new Test().run(); }int a = 2021, b = 999999999, p = 1000000007;void run() {System.out.println(pow(a, p - 2) * b % p);}long pow(int a, int n) {if (n == 1) return a;long res = pow(a, n >> 1);res = res * res % p;return (n & 1) == 1 ? res * a % p : res;}
}

  Java\mathrm{Java}Java 实现起来较为容易一点。


#B 直线

本题总分:555 分


问题描述

  在平面直角坐标系中,两点可以确定一条直线。如果有多点在一条直线上,那么这些点中任意两点确定的直线是同一条。
  给定平面上 2×32 × 32×3 个整点 {(x,y)∣0≤x<2,0≤y<3,x∈Z,y∈Z}\{(x, y)|0 ≤ x < 2, 0 ≤ y < 3, x ∈ Z, y ∈ Z\}{(x,y)∣0≤x<2,0≤y<3,x∈Z,y∈Z},即横坐标是 000 到 111 (包含 000 和 111) 之间的整数、纵坐标是 000 到 222 (包含 000 和 222) 之间的整数的点。这些点一共确定了 111111 条不同的直线。
  给定平面上 20×2120 × 2120×21 个整点 {(x,y)∣0≤x<20,0≤y<21,x∈Z,y∈Z}\{(x, y)|0 ≤ x < 20, 0 ≤ y < 21, x ∈ Z, y ∈ Z\}{(x,y)∣0≤x<20,0≤y<21,x∈Z,y∈Z},即横坐标是 000 到 191919 (包含 000 和 191919) 之间的整数、纵坐标是 000 到 202020 (包含 000 和 202020) 之间的整数的点。请问这些点一共确定了多少条不同的直线。


答案提交

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


40257


直线方程集合


  一种朴素的想法,是将所有点连接起来,去掉重复的线,然后统计。

  为了方便表示,这里采用斜截式方程 y=kx+by=kx+by=kx+b 来表示每一条直线,其中 kkk 为直线斜率,bbb 为直线在 yyy 轴上的截距,并统一不处理斜率不存在的线,将结果加上一个 202020。

  注意! 这段程序的结果是不准确的。

import java.util.HashSet;
import java.util.Set;public class Test {public static void main(String[] args) { new Test().run(); }int X = 20, Y = 21;void run() {Set<Line> set = new HashSet();for (int x1 = 0; x1 < X; x1++)for (int y1 = 0; y1 < Y; y1++)for (int x2 = x1; x2 < X; x2++)for (double y2 = 0; y2 < Y; y2++)if (x1 != x2){double k = (y2 - y1) / (x2 - x1);double b = -x1 * k + y1;set.add(new Line(k, b));}System.out.println(set.size() + X);}class Line {double k, b;Line(double b, double k) {this.k = k;this.b = b;}@Overridepublic boolean equals(Object obj) {return k == ((Line)obj).k && b == ((Line)obj).b;}@Overridepublic int hashCode() {return (int)k ^ (int)b;}}
}

分式消除误差


  斜率在浮点数表示下,精度那是参差不齐,诚然可以将误差限制在一个范围内,当绝对差落入当中时,我们就将其视为值相同。

  但是对于这种需要可表示的范围小的时候,我们可以定义分式来做到无误差,而不是控制精度。

import java.util.HashSet;
import java.util.Set;public class Test {public static void main(String[] args) { new Test().run(); }int X = 20, Y = 21;void run() {Set<Line> set = new HashSet();for (int x1 = 0; x1 < X; x1++)for (int y1 = 0; y1 < Y; y1++)for (int x2 = x1; x2 < X; x2++)for (int y2 = 0; y2 < Y; y2++)if (x1 != x2){Fraction k = new Fraction(y2 - y1, x2 - x1);Fraction b = new Fraction(y1 * (x2 - x1) - x1 * (y2 - y1),x2 - x1);set.add(new Line(k, b));}System.out.println(set.size() + X);}class Fraction {int numerator, denominator;Fraction(int numerator, int denominator) {int gcd = gcd(numerator, denominator);this.denominator = denominator /gcd;this.numerator = numerator / gcd;}int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }@Overridepublic boolean equals(Object obj) {return this.numerator == ((Fraction)obj).numerator && this.denominator == ((Fraction)obj).denominator;}}class Line {Fraction k, b;Line(Fraction b, Fraction k) {this.k = k;this.b = b;}@Overridepublic boolean equals(Object obj) {return this.k.equals(((Line)obj).k) && this.b.equals(((Line)obj).b);}@Overridepublic int hashCode() {return k.denominator;}}
}

平面几何


  这是一个平面直角坐标系,原点与 (1,2)(1,2)(1,2) 连成一条线段。


  我们将经过这两点的直线,以及这条直线经过的点与该点于横竖轴的垂线标记出来。

  显然,若直线经过 (x1,y1)(x_{1},y_{1})(x1​,y1​)、(x2,y2)(x_{2},y_{2})(x2​,y2​) 两点,那么它必然也经过 (x1+k(x1−x2),y1+k(y1−y2))(x_{1} +k(x_{1} - x_{2}),y_{1} + k(y_{1} - y_{2}))(x1​+k(x1​−x2​),y1​+k(y1​−y2​)),k∈Zk \in Zk∈Z。

  若在连接一条直线时,将所有直线经过的点标记起来,在下次遇到已经标记过的两点,我们便可直接跳过。

public class Test {public static void main(String[] args) { new Test().run(); }int X = 20, Y = 21;void run() {int count = 0;boolean[][][][] marked = new boolean[X][Y][X][Y];for (int x1 = 0; x1 < X; x1++)for (int y1 = 0; y1 < Y; y1++) {marked[x1][y1][x1][y1] = true;for (int x2 = 0; x2 < X; x2++)for (int y2 = 0; y2 < Y; y2++) {if (marked[x1][y1][x2][y2]) continue;int x = x1, y = y1, xOffset = x - x2, yOffset = y - y2;while (x >= 0 && x < X && y >= 0 && y < Y) {x += xOffset;y += yOffset;}x -= xOffset;y -= yOffset;while (x >= 0 && x < X && y >= 0 && y < Y) {for (int i = x - xOffset, j = y - yOffset; i >= 0 && i < X && j >= 0 && j < Y; i -= xOffset, j -= yOffset) {marked[x][y][i][j] = marked[i][j][x][y] = true;}x -= xOffset;y -= yOffset;}count++;}}System.out.println(count);}
}

  我觉得可能会再考个差不多的,这里给大伙一个推论。

  平面直角坐标系上有 n×nn × nn×n,n≥2n \ge 2n≥2 个点 {(x,y)∣0≤x<n,0≤y<n,x∈Z,y∈Z}\{(x, y)|0 ≤ x < n, 0 ≤ y < n, x ∈ Z, y ∈ Z\}{(x,y)∣0≤x<n,0≤y<n,x∈Z,y∈Z},从原点出发可连接的不同直线为 1≤x,y<n1 \leq x,y <n1≤x,y<n,x≠yx \ne yx​=y 中 gcd(x,y)=1gcd(x,y) = 1gcd(x,y)=1 的次数加 333。

  感兴趣的读者可以自行证明。

  同时在 1≤x<y<n1 \leq x < y < n1≤x<y<n 时,gcd(x,y)=1gcd(x,y) = 1gcd(x,y)=1 的出现次数恰好等于 ∑y=2n−1φ(y)\displaystyle\sum_{y = 2}^{n-1}\varphi(y)y=2∑n−1​φ(y),其中 φ\varphiφ 为欧拉函数。

  能力有限,这里便不再继续讨论。


#C 货物摆放

本题总分:101010 分


问题描述

  小蓝有一个超大的仓库,可以摆放很多货物。
  现在,小蓝有 nnn 箱货物要摆放在仓库,每箱货物都是规则的正方体。小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、宽、高。
  小蓝希望所有的货物最终摆成一个大的立方体。即在长、宽、高的方向上分别堆 L、W、HL、W、HL、W、H 的货物,满足 n=L×W×Hn = L × W × Hn=L×W×H。
  给定 nnn,请问有多少种堆放货物的方案满足要求。
  例如,当 n=4n = 4n=4 时,有以下 666 种方案:1×1×41×1×41×1×4、1×2×21×2×21×2×2、1×4×11×4×11×4×1、2×1×22×1×22×1×2、2×2×12 × 2 × 12×2×1、4×1×14 × 1 × 14×1×1。
  请问,当 n=2021041820210418n = 2021041820210418n=2021041820210418 (注意有 161616 位数字)时,总共有多少种方案?
  提示:建议使用计算机编程解决问题。


答案提交

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


2430


暴力搜索


  每届必考的基本算术定理。

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;public class Test {public static void main(String[] args) { new Test().run(); }long n = 2021041820210418L;void run() {List<Integer> exps0 = new ArrayList();ArrayDeque<Integer> exps1 = new ArrayDeque();for (int k = 2; k <= n; k++)if (n % k == 0) {int e = 0;while (n % k == 0) {n /= k;e++;}exps0.add(e);}System.out.println(dfs(exps0, exps1, 0));}int dfs(List<Integer> exps0, ArrayDeque<Integer> exps1, int cur) {if (cur == exps0.size()) {int comb = 1;for (int exp : exps1)comb *= exp + 1;return comb;}int ans = 0;for (int i = exps0.get(cur); i >= 0; i--) {exps1.push(i);ans += dfs(exps0, exps1, cur + 1);exps1.pop();}return ans;}
}

  直接套两 for 也不是不行,但这么写出来的程序,通常到比赛结束都跑不完。

  因此我们要避免无效因子的判断,

  这里统计的为质因子分成三份,可能的组合个数,它与原命题等价。

  没什么好讲的。


缩放质因子


  举个例子,

  当 n=9n = 9n=9  时,有 666 种方案:1×1×91×1×91×1×9、1×3×31×3×31×3×3、1×9×11×9×11×9×1、3×1×33×1×33×1×3、3×3×13 × 3 × 13×3×1、9×1×19 × 1 × 19×1×1;

  当 n=25n = 25n=25 时,有 666 种方案:1×1×251×1×251×1×25、1×5×51×5×51×5×5、⋯\cdots⋯ ;

  当 n=p2n =p^{2^{}}n=p2 时,有 666 种方案:1×1×p21×1×p^{2}1×1×p2、1×p×p1×p×p1×p×p、⋯\cdots⋯ ;

  其中 ppp 为质数。

  其实上例解法当中,我们就能发现,组合的个数与其具体的值无关,它只与质因数指数挂钩。

  2021041820210418=2×33×17×131×2857×58823532021041820210418 = 2 × 3^3 × 17 × 131 × 2857 × 58823532021041820210418=2×33×17×131×2857×5882353

  如果我们找最小的几个质数来代替它们,得到的新数字 23×3×5×7×11×13=1201202^3 × 3 × 5 × 7 × 11 × 13 = 12012023×3×5×7×11×13=120120 与 202104182021041820210418202104182021041820210418 在这个命题下等价。

  而 120120120120120120 的大小就足够我们真暴搜把它的全部因数组合找到了。

import java.util.ArrayList;
import java.util.List;public class Test {public static void main(String[] args) { new Test().run(); }long N = 2021041820210418L;void run() {List<Integer> exps = new ArrayList();for (int k = 2; k <= N; k++)if (N % k == 0) {int e = 0;while (N % k == 0) {N /= k;e++;}exps.add(e);}exps.sort((a, b) -> (b - a));int n = 1, p = 2, ans = 0;for (int exp : exps) {for (int i = 2; i * i <= p; i++)if (p % i == 0) {i = 1;p++;}while (exp-- > 0) n *= p;p++;}for (int a = 1; a <= n; a++)if (n % a == 0)for (int b = 1; b <= n; b++)if (n / a % b == 0) ans++;System.out.println(ans);}
}

#D 路径

本题总分:101010 分


问题描述

  小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图中的最短路径。
  小蓝的图由 202120212021 个结点组成,依次编号 111 至 202120212021。对于两个不同的结点 a,ba, ba,b,如果 aaa 和 bbb 的差的绝对值大于 212121,则两个结点之间没有边相连;如果 aaa 和 bbb 的差的绝对值小于等于 212121,则两个点之间有一条长度为 aaa 和 bbb 的最小公倍数的无向边相连。
  例如:结点 111 和结点 232323 之间没有边相连;结点 333 和结点 242424 之间有一条无向边,长度为 242424;结点 151515 和结点 252525 之间有一条无向边,长度为 757575。
  请计算,结点 111 和结点 202120212021 之间的最短路径长度是多少。
  提示:建议使用计算机编程解决问题。


答案提交

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


10266837


  题目已经说的够清楚了,

  建一个有 202120212021 个顶点 21×2000+21(21+1)221 × 2000 + \cfrac{21(21 + 1)}{2}21×2000+221(21+1)​ 条边的无向图,跑图上的算法就完事了。

  还有的细节就是整形是否会溢出,我们取 (1,2021](1,2021](1,2021] 中最大的质数 201720172017 与 202122021^220212 相乘,得到的结果还是有点夸张的,虽然经过测试,可能的线路权值合至多不会超过 231−12^{31} - 1231−1,但毕竟是面向竞赛,考虑甄别的时间成本,直接使用长整形更为划算。


搜索


深度优先搜索


  202120212021 个顶点,绝大多数顶点都连有 2×212 × 212×21 条边,

  别深搜了,一搜就是

  compilaition completed successfully in 500ms(4 hour ago)

  就,电脑跟选手对着坐牢。


记忆化搜索


  深度优先搜索,在搜索最优结果时,通常需要完整的枚举全部可能的问题状态。

  但在这个问题状态的集合中,所有可选方案的 “后缀” 都是相同,也就是所有可选的分支,它们都是以同一个节点结尾。

  如果我们将已经搜索到的节点到目标节点间的最短路径保存下来,在再次搜索到这个 “后缀” 的分支时直接返回。

  那么问题就可能在一个较短的时间内解决。

  这也是所谓的记忆化搜索。

import java.util.ArrayList;
import java.util.List;public class Test {public static void main(String[] args) { new Test().run(); }int N = 2021;int[] weight = new int[N + 1];List<Edge>[] graph = new List[N + 1];boolean[] visited = new boolean[N + 1];void run() {for (int i = 1; i <= N; i++)graph[i] = new ArrayList();for (int v = 1; v <  N; v++)for (int w = v + 1; w <= min(v + 21, N);  w++) {graph[v].add(new Edge(w, lcm(v, w)));graph[w].add(new Edge(v, lcm(v, w)));}visited[1] = true;System.out.println(dfs(1));}int dfs(int v) {if (v == N) return 0;if (weight[v] != 0) return weight[v];int min = 0x7FFFFFFF;for (Edge edge : graph[v]) {if (visited[edge.w]) continue;visited[edge.w] = true;min = min(min, dfs(edge.w) + edge.weight);visited[edge.w] = false;}return weight[v] = min;}int min(int a, int b) { return a < b ? a : b; }int lcm(int a, int b) { return a * b / gcd(a, b); }int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }class Edge {int w, weight;Edge(int w, int weight) {this.weight = weight;this.w = w;}}
}

枝剪广搜


  其实朴素的去搜索,不论深搜还是广搜,在竞赛里都是很冒进的行为,

  影响这两个算法执行效率的因素太多。

  当然要是没有其他的思路,也只能死马当活马医了。

  幸运的是,只需简单的枝剪,就能在很短的时间计算出结果

import java.util.PriorityQueue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Queue;
import java.util.List;public class Test {public static void main(String[] args) { new Test().run(); }int N = 2021;void run() {List<Edge>[] graph = new List[N + 1];long[] visited = new long[N + 1];for (int i = 1; i <= N; i++)graph[i] = new ArrayList();for (int v = 1; v <  N; v++)for (int w = v + 1; w <= min(v + 21, N);  w++) {graph[v].add(new Edge(w, lcm(v, w)));graph[w].add(new Edge(v, lcm(v, w)));}Queue<Vertex> queue = new PriorityQueue();Arrays.fill(visited, Long.MAX_VALUE);queue.offer(new Vertex(1, 0));Vertex V = null;while (queue.size() > 0) {V = queue.poll();if (V.v == N) break;if (V.weight >= visited[V.v]) continue;visited[V.v] = V.weight;for (Edge edge : graph[V.v])queue.offer(new Vertex(edge.w, edge.weight + V.weight));}System.out.println(V.weight);}int min(int a, int b) { return a < b ? a : b; }int lcm(int a, int b) { return a * b / gcd(a, b); }int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }class Edge {int w, weight;Edge(int w, int weight) {this.weight = weight;this.w = w;}}class Vertex implements Comparable<Vertex> {int v;long weight;Vertex(int v, long weight) {this.weight = weight;this.v = v;}@Overridepublic int compareTo(Vertex V) { return Long.compare(this.weight, V.weight); }}
}

单源最短路径


Dijkstra


  题目给出的图显然是个边加权,权重非负的无向图,跑遍 DijkstraDijkstraDijkstra 就完事了。

import java.util.PriorityQueue;
import java.util.ArrayList;
import java.util.Queue;
import java.util.List;public class Test {public static void main(String[] args) { new Test().run(); }int N = 2021;void run() {boolean[] marked = new boolean[N + 1];List<Edge>[] graph = new List[N + 1];long[] distTo = new long[N + 1];for (int i = 1; i <= N; i++) {graph[i] = new ArrayList();distTo[i] = Long.MAX_VALUE;}for (int v = 1; v <  N; v++)for (int w = v + 1; w <= min(v + 21, N);  w++) {graph[v].add(new Edge(w, lcm(v, w)));graph[w].add(new Edge(v, lcm(v, w)));}Queue<Vertex> queue = new PriorityQueue();queue.offer(new Vertex(1, distTo[1] = 0));while (queue.size() > 0) {Vertex V = queue.poll();if (marked[V.v])continue;marked[V.v] = true;for (Edge edge : graph[V.v])if (distTo[edge.w] > distTo[V.v] + edge.weight)queue.offer(new Vertex(edge.w, distTo[edge.w] = distTo[V.v] + edge.weight));}System.out.println(distTo[N]);}int min(int a, int b) { return a < b ? a : b; }int lcm(int a, int b) { return a * b / gcd(a, b); }int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }class Edge {int w, weight;Edge(int w, int weight) {this.weight = weight;this.w = w;}}class Vertex implements Comparable<Vertex> {int v;long dist;Vertex(int v, long dist) {this.dist = dist;this.v = v;}@Overridepublic int compareTo(Vertex V) { return Long.compare(this.dist, V.dist); }}
}

Floyd


  如果是一道最短路径的结果题。

  竞赛时限内能运行完 O(n3)O(n^{3})O(n3) 的程序。

  那其实无脑套 FloydFloydFloyd 就行。

public class Test {public static void main(String[] args) { new Test().run(); }int N = 2021;void run() {long[][] floyd = new long[N + 1][N + 1];for (int v = 1; v < N; v++)for (int w = v + 1; w <= min(N, v + 21); w++)floyd[v][w] = floyd[w][v] = lcm(v, w);for (int k = 1; k <= N; k++)for (int v = 1; v <= N; v++)if (floyd[v][k] == 0) continue;else for (int w = 1; w <= N; w++)if (floyd[k][w] == 0) continue;else if (floyd[v][w] == 0 || floyd[v][k] + floyd[k][w] < floyd[v][w])floyd[v][w] = floyd[v][k] + floyd[k][w];System.out.println(floyd[1][N]);}long min(int a, int b) { return a < b ? a : b; }int lcm(int a, int b) { return a * b / gcd(a, b); }int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
}

  半分钟就出来了,还行。


#E 回路计数

本题总分:151515 分


问题描述

  蓝桥学院由 212121 栋教学楼组成,教学楼编号 111 到 212121。对于两栋教学楼 aaa 和 bbb,当 aaa 和 bbb 互质时,aaa 和 bbb 之间有一条走廊直接相连,两个方向皆可通行,否则没有直接连接的走廊。
  小蓝现在在第一栋教学楼,他想要访问每栋教学楼正好一次,最终回到第一栋教学楼(即走一条哈密尔顿回路),请问他有多少种不同的访问方案?两个访问方案不同是指存在某个 iii,小蓝在两个访问方法中访问完教学楼 iii 后访问了不同的教学楼。
  提示:建议使用计算机编程解决问题。


答案提交

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


881012367360


记忆化搜索


  题目描述显然能构成边集大小为 ∑i=121φ(i)=140\displaystyle\sum_{i=1}^{21} \varphi (i) = 140i=1∑21​φ(i)=140 的无向图,遍历图的复杂度估算为O(∏i=1nφ(i))O(\prod_{i=1}^n \varphi(i))O(∏i=1n​φ(i)),

  暴力去搜索似乎不太可行,但我们可借助一定的优化手段,以及记忆化处理来使它在一个可接受的时间内计算出结果。

  设 fv,statusf_{v,status}fv,status​ 为从 vvv 点开始,历经 statusstatusstatus 的方案数,statusstatusstatus 在二进制表示下,第 iii 位为 111 表示需要经过 iii 点。

  则答案为 ∑v=221fv,status−v−1\displaystyle\sum_{v = 2}^{21} f_{v,status - v-1}v=2∑21​fv,status−v−1​,因为 111 与 如何大于 111 的整数互质,也就是说从任意点都可以到 111 号点,我们只需要统计经过除一号点遍历全图的路径数就行了。

  然后将 [2,n][2,n][2,n] 映射到 [0,n−2][0, n - 2][0,n−2] 优化一定的性能,

  最后 333s 就能运行出现,还是挺意外的。

import java.util.ArrayList;
import java.util.List;public class Test {public static void main(String[] args) { new Test().run(); }int N = 21;long[][] cnt = new long[N - 1][1 << N - 1];List<Integer>[] graph = new List[N];void run() {for (int i = 0; i < N; i++)graph[i] = new ArrayList();for (int i = 2; i <= N; i++)for (int j = 2; j < i; j++)if (gcd(i, j) == 1){graph[i - 2].add(j - 2);graph[j - 2].add(i - 2);}for (int i = 0; i < cnt.length; i++)for (int j = 0; j < cnt[i].length; j++) cnt[i][j] = -1;long sum = 0;for (int i = 0; i < N - 1; i++)sum += dfs(i, (1 << N - 1) - 1 - (1 << i));System.out.println(sum);}long dfs(int start, int status) {if (status == 0) return 1;if (cnt[start][status] != -1) return cnt[start][status];long sum = 0;for (int v : graph[start])if ((status & (1 << v)) > 0)sum += dfs(v, status - (1 << v));return cnt[start][status] = sum;}int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
}

  记忆化搜索就是状压dp\mathrm{dp}dp的递归实现,

  写给 A\mathrm{A}A 组的话没有什么实现的必要,

  就是提一句。

  笔算 φ\varphiφ 不费事,但可以直接用 n(n−1)2−nln⁡n\cfrac{n(n - 1)}{2} - n \ln n2n(n−1)​−nlnn 估算,

  (1,n](1,n](1,n] 间所有整数的因数之和约为 nln⁡nn \ln nnlnn,

  一眼暴力牡蛎。


#F 最少砝码

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


问题描述

  你有一架天平。现在你要设计一套砝码,使得利用这些砝码可以称出任意小于等于 NNN 的正整数重量。
  那么这套砝码最少需要包含多少个砝码?
  注意砝码可以放在天平两边。


输入格式

  输入包含一个正整数 NNN。


输出格式

  输出一个整数代表答案。


测试样例1

Input:
7Output:
3Explanation:
3 个砝码重量是 1、4、6,可以称出 1 至 7 的所有重量。
1 = 1;
2 = 6 − 4 (天平一边放 6,另一边放 4);
3 = 4 − 1;
4 = 4;
5 = 6 − 1;
6 = 6;
7 = 1 + 6;
少于 3 个砝码不可能称出 1 至 7 的所有重量。

评测用例规模与约定

  对于所有评测用例,1≤N≤10000000001 ≤ N ≤ 10000000001≤N≤1000000000。


变种三进制


  一个集合中包含 nnn 个数,任取若干数可以加减出任意小于等于 NNN 的正整数。

  首先要考虑怎么去满足题目要求的性质,

  设第 iii 个砝码的重量为 wiw_{i}wi​,原集合 AN={w1,w2,⋯,wn}A_{N} = \{w_{1},w_{2},\cdots,w_{n}\}AN​={w1​,w2​,⋯,wn​}。

  要满足题意首先要有 sum(A)≥Nsum(A) \ge Nsum(A)≥N,

  设我们知道了 A⌊N/3⌋A_{\lfloor N/3 \rfloor}A⌊N/3⌋​ 的方案,那么我们就能在这个方案里加入一个 2⌊N/3⌋+12\lfloor N/3 \rfloor + 12⌊N/3⌋+1,就能用 2⌊N/3⌋+12\lfloor N/3 \rfloor + 12⌊N/3⌋+1 对 A⌊N/3⌋A_{\lfloor N/3 \rfloor}A⌊N/3⌋​ 中个若干元素做差表示出 (⌊N/3⌋,2⌊N/3⌋+1)(\lfloor N/3 \rfloor, 2\lfloor N/3 \rfloor + 1)(⌊N/3⌋,2⌊N/3⌋+1),对若干元素求和表示出 (2⌊N/3⌋+1,N](2\lfloor N/3 \rfloor + 1, N](2⌊N/3⌋+1,N],并入 A⌊N/3⌋A_{\lfloor N/3 \rfloor}A⌊N/3⌋​ 本身能表示的范围,即能表示出任意小于等于 NNN 的正整数。

  如果 A⌊N/3⌋A_{\lfloor N/3 \rfloor}A⌊N/3⌋​ 本身是最优的,那么往里面加入 K=2⌊N/3⌋+1K = 2\lfloor N/3 \rfloor + 1K=2⌊N/3⌋+1 的 ANA_NAN​ 也一定是最优的,因为要使得 K+sum(A⌊N/3⌋)≥NK + sum(A_{\lfloor N/3 \rfloor}) \ge NK+sum(A⌊N/3⌋​)≥N,KKK 必须大于等于 2⌊N/3⌋+12\lfloor N/3 \rfloor + 12⌊N/3⌋+1,而当 K>2⌊N/3⌋+1K > 2\lfloor N/3 \rfloor + 1K>2⌊N/3⌋+1 时,就无法表示出 ⌊N/3⌋+1\lfloor N/3 \rfloor + 1⌊N/3⌋+1,

  当然这一切还有个前提条件,那就是 sum(A⌊N/3⌋)=⌊N/3⌋sum(A_{\lfloor N/3 \rfloor}) = \lfloor N/3 \rfloorsum(A⌊N/3⌋​)=⌊N/3⌋。’

  不过到这里已经足够启发我们去顺推了,

  因为这个问题的边界是显然的,

  当 N=1N = 1N=1 时,A1={1}A_{1} = \{1\}A1​={1},

  我们往 A1A_{1}A1​ 中加入 2×sum(A1)+12 × sum(A_{1}) + 12×sum(A1​)+1,得到 A4A_{4}A4​,即

  当 N=4N = 4N=4 时,A4={1,3}A_{4} = \{1,3\}A4​={1,3},

  当 N=13N = 13N=13 时,A13={1,3,9}A_{13} = \{1,3,9\}A13​={1,3,9},

  ⋯⋯\cdots \cdots⋯⋯

  当然还存在 NNN 不在我们找到的最优规律中。

  我们设 N=5N = 5N=5,

  因为 A4={1,3}A_{4} = \{1,3\}A4​={1,3} 的最优性,222 个元素至多组成任意小于等于 444 的正整数,

  因为 A13={1,3,9}A_{13} = \{1,3,9\}A13​={1,3,9} 的最优性,333 个元素可以表示任意小于等于 131313 的正整数。

  即对 N=5N = 5N=5 给出的答案,必须大于 222 小于等于 333。

  对于给出任意 NNN 我们都可以按照这个性质求出答案。

  同时在三进制下来看这个规律:

  {N}={(1)3,(11)3,(11)3,⋯}\{N\} = \{(1)_{3},(11)_{3},(11)_{3},\cdots\}{N}={(1)3​,(11)3​,(11)3​,⋯}

  可以二分,但没有必要。

import java.util.Scanner;public class Main {public static void main(String[] args) { new Main().run(); }void run() {long N = new Scanner(System.in).nextLong(), ans = 1;for (long pow3 = 1; pow3 < N; pow3 = pow3 * 3 + 1, ans++);System.out.println(ans);}
}

  写的稀烂,主要这题目出的就恶心人。


#G 左孩子右兄弟

时间限制: 3.0s3.0\mathrm s3.0s 内存限制: 512.0MB512.0\mathrm{MB}512.0MB 本题总分:202020 分


问题描述

  对于一棵多叉树,我们可以通过 “左孩子右兄弟” 表示法,将其转化成一棵二叉树。
  如果我们认为每个结点的子结点是无序的,那么得到的二叉树可能不唯一。换句话说,每个结点可以选任意子结点作为左孩子,并按任意顺序连接右兄弟。
  给定一棵包含 NNN 个结点的多叉树,结点从 111 至 NNN 编号,其中 111 号结点是根,每个结点的父结点的编号比自己的编号小。请你计算其通过 “左孩子右兄弟” 表示法转化成的二叉树,高度最高是多少。注:只有根结点这一个结点的树高度为 000 。
  例如如下的多叉树:

  可能有以下 333 种 (这里只列出 333 种,并不是全部) 不同的 “左孩子右兄弟”表示:

  其中最后一种高度最高,为 444。


输入格式

  输入的第一行包含一个整数 NNN。
  以下 N−1N −1N−1 行,每行包含一个整数,依次表示 222 至 NNN 号结点的父结点编号。


输出格式

  输出一个整数表示答案。


测试样例1

Input:
5
1
1
1
2Output:
4

评测用例规模与约定

  对于 303030% 的评测用例,1≤N≤201 ≤ N ≤ 201≤N≤20;
  对于所有评测用例,1≤N≤1000001 ≤ N ≤ 1000001≤N≤100000。


树形 DP


  一棵树的高度等于根节点最高子树的高度加一,

  而一棵由左孩子右兄弟表示法得到的二叉树,

  我们可以将最大的子树放在最右边,

  这种策略下,每棵子树的高度为子树个数加最高子树高度。

  显 然 正 确

  于是有状态转移方程:dp(v)=count(son(v))+max{dp(son(v))}dp(v) = \mathrm{count(son(}v\mathrm{))} + \mathrm{max\{}dp\mathrm{(son(}v\mathrm{))\}}dp(v)=count(son(v))+max{dp(son(v))}

import java.io.*;
import java.util.*;public class Main {public static void main(String[] args) { new Main().run(); }List<Integer>[] tree;void run() {InputReader in = new InputReader(System.in);int n = in.readInt(), v;tree = new List[n + 1];for (int w = 2; w <= n; w++) {v = in.readInt();if (tree[v] == null)tree[v] = new ArrayList();tree[v].add(w);}System.out.println(dp(1));}int dp(int v) {if (tree[v] == null) return 0;int max = 0;for (int w : tree[v])max = Math.max(max, dp(w));return tree[v].size() +  max;}class InputReader {BufferedReader reader;StringTokenizer token;InputReader(InputStream in) {this.reader = new BufferedReader(new InputStreamReader(in));}String read() {while (token == null || !token.hasMoreTokens()) {try {token = new StringTokenizer(reader.readLine());} catch (IOException e) {e.printStackTrace();}}return token.nextToken();}int readInt() { return Integer.parseInt(read()); }}
}

#H 异或数列

时间限制: 2.0s2.0\mathrm s2.0s 内存限制: 512.0MB512.0\mathrm{MB}512.0MB 本题总分:202020 分


  Alice\mathrm{Alice}Alice 和 Bob\mathrm{Bob}Bob 正在玩一个异或数列的游戏。初始时,Alice\mathrm{Alice}Alice 和 Bob\mathrm{Bob}Bob 分别有一个整数 aaa 和 bbb,有一个给定的长度为 nnn 的公共数列 X1,X2,⋯,XnX_1, X_2, \cdots , X_nX1​,X2​,⋯,Xn​。
  Alice\mathrm{Alice}Alice 和 Bob\mathrm{Bob}Bob 轮流操作,Alice\mathrm{Alice}Alice 先手,每步可以在以下两种选项中选一种:
  选项 111:从数列中选一个 XiX_iXi​ 给 Alice\mathrm{Alice}Alice 的数异或上,或者说令 aaa 变为 a⊕Xia ⊕ X_ia⊕Xi​。(其中 ⊕⊕⊕ 表示按位异或)
  选项 222:从数列中选一个 XiX_iXi​ 给 Bob\mathrm{Bob}Bob 的数异或上,或者说令 bbb 变为 b⊕Xib ⊕ X_ib⊕Xi​。
  每个数 XiX_iXi​ 都只能用一次,当所有 XiX_iXi​ 均被使用后(nnn 轮后)游戏结束。游戏结束时,拥有的数比较大的一方获胜,如果双方数值相同,即为平手。
  现在双方都足够聪明,都采用最优策略,请问谁能获胜?


输入格式

  每个评测用例包含多组询问。询问之间彼此独立。
  输入的第一行包含一个整数 TTT,表示询问数。
  接下来 TTT 行每行包含一组询问。其中第 iii 行的第一个整数 nin_ini​ 表示数列长度,随后 nin_ini​ 个整数 X1,X2,⋯,XniX_1, X_2, \cdots , X_{ni}X1​,X2​,⋯,Xni​ 表示数列中的每个数。


输出格式

  输出 TTT 行,依次对应每组询问的答案。
  每行包含一个整数 111、000 或 −1−1−1 分别表示 Alice\mathrm{Alice}Alice 胜、平局或败。


测试样例1

Input:
4
1 1
1 0
2 2 1
7 992438 1006399 781139 985280 4729 872779 563580Output:
1
0
1
1

评测用例规模与约定

  对于所有评测用例,1≤T≤2000001 \leq T \leq 2000001≤T≤200000,1≤∑i=1Tni≤2000001 \leq \sum_{i=1}^T n_i \leq 2000001≤∑i=1T​ni​≤200000,0≤Xi<2200 \leq X_i < 2^{20}0≤Xi​<220。


博弈论


  题目没看太懂,不过没说那 aaa、bbb 初始值应该为 000 吧。

  首先我们来回顾一下公平组合游戏的定义。

  1):游戏有两名玩家参与,二者轮流做出决策,双方均知道游戏的完整信息。

  2):任意一位玩家在某一确定状态可以作出的决策集合只与当前的状态有关,与玩家无关。

  3):游戏中的同一个状态不可能多次抵达,游戏以玩家无法行动为结束,且游戏一定会在有限步后以非平局结束。

  因此我们需要将平局与非平局状态分开讨论,以便应用一些博弈论有关的结论。

  对于 Alice\mathrm{Alice}Alice 和 Bob\mathrm{Bob}Bob 平局,仅在存在 a⊕XI1⊕XI2⊕⋯⊕XIn=b⊕XJ1⊕XJ2⊕⋯⊕XJma \oplus X_{I_1} \oplus X_{I_2} \oplus\cdots\oplus X_{I_n} = b \oplus X_{J_1} \oplus X_{J_2} \oplus\cdots\oplus X_{J_m}a⊕XI1​​⊕XI2​​⊕⋯⊕XIn​​=b⊕XJ1​​⊕XJ2​​⊕⋯⊕XJm​​,I∪J=[1,ni]I\cup J = [1,n_i]I∪J=[1,ni​]、I∩J=∅I\cap J = \varnothingI∩J=∅。

  我们可以简单的从恒等率 a⊕0=aa \oplus 0 = aa⊕0=a,和归零率 a⊕a=0a \oplus a = 0a⊕a=0 中得到 a⊕XI1⊕XI2⊕⋯⊕XIn⊕b⊕XJ1⊕XJ2⊕⋯⊕XJm=0a \oplus X_{I_1} \oplus X_{I_2} \oplus\cdots\oplus X_{I_n} \oplus b \oplus X_{J_1} \oplus X_{J_2} \oplus\cdots\oplus X_{J_m}= 0a⊕XI1​​⊕XI2​​⊕⋯⊕XIn​​⊕b⊕XJ1​​⊕XJ2​​⊕⋯⊕XJm​​=0,

  即当 X1⊕X2⊕⋯⊕Xni=0X_1 \oplus X_2 \oplus\cdots\oplus X_{n_i}= 0X1​⊕X2​⊕⋯⊕Xni​​=0 时 对于 Alice\mathrm{Alice}Alice 和 Bob\mathrm{Bob}Bob 平局,而且显然当此式不成立时,无论如何都找不到一对集合 III、JJJ 使得上式成立。

  现在再回顾一下公平组合游戏的定理。

  1):没有后继状态的状态是必败状态。

  2):一个状态是必胜状态,当且仅当存在至少一个必败状态为它的后继状态。

  3):一个状态是必败状态,当且仅当它的所有后继状态均为必胜状态。

  还是挂个 资料的链接 在这吧。

  此外我们将自然数 aaa、bbb 的大小关系推广一下,a>ba > ba>b,当存在一个最大的 iii,满足 aaa、bbb 大于 iii 位的数字完全相等,aaa 的第 iii 位数字大于 bbb 的第 iii 位数字。

  设 c=X1⊕X2⊕⋯⊕Xnic = X_1 \oplus X_2 \oplus\cdots\oplus X_{n_i}c=X1​⊕X2​⊕⋯⊕Xni​​,对于超出 ccc 位数的部分,无论怎么选择,最后总是相等的,对于 ccc 的最高位 cic_ici​,若它在 XXX 中只出现 111 次,Alice\mathrm{Alice}Alice 选择它即必胜,若它出现奇数次(不可能为偶数次),设其集合为 X′X'X′,

  若 Alice\mathrm{Alice}Alice 先从 X′X'X′ 中选择数字,余下的数字相与结果 ci=0c_i = 0ci​=0,但这并不代表 Alice\mathrm{Alice}Alice 必赢,因为若 nin_ini​ 为偶数,则在 Alice\mathrm{Alice}Alice 先手从 X′X'X′ 中选择数字的情况下,Bob\mathrm{Bob}Bob 总有办法能让 Alice\mathrm{Alice}Alice 第二个从 X′X'X′ 中选择数字,此时 Alice\mathrm{Alice}Alice 必败,反之必胜。

  若 Alice\mathrm{Alice}Alice 先从 CXX′C_{X}X'CX​X′ 中选择数字,也是同理。

  因此答案只与 X′X'X′ 的大小,与 nnn 的奇偶性相关。

import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;public class Main {public static void main(String[] args) { new Main().run(); }void run() {InputReader in = new InputReader(System.in);PrintWriter out = new PrintWriter(System.out);int T = in.readInt(), S, n, a;int[] A = new int[21];while (T-- > 0) {S = 0;n = in.readInt();Arrays.fill(A, 0);boolean flag = (n & 1) == 1;while (n-- > 0) {S ^= a = in.readInt();for (int i = 0; i <= 20; i++)if ((a >> i & 1) == 1) A[i]++;}if (S == 0) out.println("0");else if (A[floorLog2(S)] == 1 || flag) out.println("1");else out.println("-1");}out.flush();}int highBit(int a) {a |= a >> 1;a |= a >> 2;a |= a >> 4;a |= a >> 8;a |= a >> 16;return a - (a >>> 1);}int[] FLOOR_LOG2_TABLE = { 0, 0, 1, 26, 2, 23, 27, 32, 3, 16, 24, 30, 28, 11, 33, 13, 4, 7, 17, 35, 25, 22, 31, 15, 29, 10, 12, 6, 34, 21, 14, 9, 5, 20, 8, 19, 18 };int floorLog2(int a) { return FLOOR_LOG2_TABLE[highBit(a) % 37]; }class InputReader {BufferedReader reader;StringTokenizer token;InputReader(InputStream in) {this.reader = new BufferedReader(new InputStreamReader(in));}String read() {while (token == null || !token.hasMoreTokens()) {try {token = new StringTokenizer(reader.readLine());} catch (IOException e) {e.printStackTrace();}}return token.nextToken();}int readInt() { return Integer.parseInt(read()); }}
}

  也可以放弃常数阶空间复杂度,减小时间复杂度上的一个较大的系数。

  提一嘴。


#I 双向排序

时间限制: 5.0s5.0\mathrm s5.0s 内存限制: 512.0MB512.0\mathrm{MB}512.0MB 本题总分:252525 分


问题描述

  给定序列 (a1,a2,⋅⋅⋅,an)=(1,2,⋅⋅⋅,n)(a_{1}, a_{2}, · · · , a_{n}) = (1, 2, · · · , n)(a1​,a2​,⋅⋅⋅,an​)=(1,2,⋅⋅⋅,n),即 ai=ia_{i} = iai​=i。
  小蓝将对这个序列进行 mmm 次操作,每次可能是将 a1,a2,⋅⋅⋅,aqia_{1}, a_{2}, · · · , a_{q_{i}}a1​,a2​,⋅⋅⋅,aqi​​ 降序排列,或者将 aqi,aqi+1,⋅⋅⋅,ana_{q_{i}}, a_{q_{i+1}}, · · · , a_{n}aqi​​,aqi+1​​,⋅⋅⋅,an​ 升序排列。
  请求出操作完成后的序列。


输入格式

  输入的第一行包含两个整数 n,mn, mn,m,分别表示序列的长度和操作次数。
  接下来 mmm 行描述对序列的操作,其中第 iii 行包含两个整数 pi,qip_{i}, q_{i}pi​,qi​ 表示操作类型和参数。当 pi=0p_{i} = 0pi​=0 时,表示将 a1,a2,⋅⋅⋅,aqia_{1}, a_{2}, · · · , a_{q_{i}}a1​,a2​,⋅⋅⋅,aqi​​ 降序排列;当 pi=1p_{i} = 1pi​=1 时,表示将 aqi,aqi+1,⋅⋅⋅,ana_{q_{i}}, a_{q_{i+1}}, · · · , a_{n}aqi​​,aqi+1​​,⋅⋅⋅,an​ 升序排列。


输出格式

  输出一行,包含 nnn 个整数,相邻的整数之间使用一个空格分隔,表示操作完成后的序列。


测试样例1

Input:
3 3
0 3
1 2
0 2Output:
3 1 2Explanation:
原数列为 (1, 2, 3)。
第 1 步后为 (3, 2, 1)。
第 2 步后为 (3, 1, 2)。
第 3 步后为 (3, 1, 2)。与第 2 步操作后相同,因为前两个数已经是降序了。

评测用例规模与约定

  对于 303030% 的评测用例,n,m≤1000n, m ≤ 1000n,m≤1000;
  对于 606060% 的评测用例,n,m≤5000n, m ≤ 5000n,m≤5000;
  对于所有评测用例,1≤n,m≤1000001 ≤ n, m ≤ 1000001≤n,m≤100000,0≤pi≤10 ≤ p_{i} ≤ 10≤pi​≤1,1≤qi≤n1 ≤ q_{i} ≤ n1≤qi​≤n;


去冗操作


  其实看到这个数据规模,五分钟写完 Brute Force,就可以下一道了,O(mnlog⁡n)O(mn \log n)O(mnlogn) 就能过 606060% 的用例,

  多的时间去证明其他程序的正确性可能收益会高点。

  不过,骗分就多骗两个吧。

  对于连续且 pip_{i}pi​ 相同操作,在 pi=0p_{i} = 0pi​=0 时只需要做 qiq_{i}qi​ 最大的操作,在 pi=1p_{i} = 1pi​=1 时只需要做 qiq_{i}qi​ 最小的操作,如图:


  显然去掉冗余操作后,还是和原操作是等价的,只需要建立一个栈就能在线性时间内完成去冗,并且代码量较少。

  特别的,我可以先将 (p:1,q:1)(p:1,q:1)(p:1,q:1) 压入栈底。

import java.io.*;
import java.util.*;public class Main {public static void main(String[] args) { new Main().run(); }void run() {InputReader in = new InputReader(System.in);PrintWriter out = new PrintWriter(System.out);int n = in.readInt(), m = in.readInt();Deque<Step> deque = new ArrayDeque();deque.push(new Step(1, 1));while (m-- > 0) {int p = in.readInt();int q = in.readInt();while (deque.size() > 0 && deque.peek().p == p)if (p == 0)q = max(q, deque.pop().q);elseq = min(q, deque.pop().q);deque.push(new Step(p, q));}Integer[] ans = new Integer[n];for (int i = 0; i < n; i++)ans[i] = i + 1;deque.pollLast();while (deque.size() > 0) {Step step = deque.pollLast();if (step.p == 0)Arrays.sort(ans, 0, step.q, (a, b)->(b - a));elseArrays.sort(ans, step.q - 1, n);}for (int i = 0; i < n; i++) {out.print(ans[i]);out.print(' ');}out.flush();}int max(int a, int b) { return a > b ? a : b; }int min(int a, int b) { return a < b ? a : b; }class Step {int p, q;Step(int p, int q) {this.p = p;this.q = q;}}class InputReader {BufferedReader reader;StringTokenizer token;InputReader(InputStream in) {this.reader = new BufferedReader(new InputStreamReader(in));}String read() {while (token == null || !token.hasMoreTokens()) {try {token = new StringTokenizer(reader.readLine());} catch (IOException e) {e.printStackTrace();}}return token.nextToken();}int readInt() { return Integer.parseInt(read()); }}
}

填数游戏


  其实最开始就想直接写到这一步,

  但是我忙的同时又有点闲,就拆开写吧。

  经过上述去冗操作,可以发现,最后需要操作的是一个 p0∣1p \ 0\mid 1p 0∣1 交替的序列,为了便于读者理解,

  这里将原序列和操作抽象成不等长不同色线段,

  特别的,原序列和 p=1p = 1p=1 的操作是一个颜色,因为原序列本就是升序。


  将 p=0p=0p=0 和 p=1p=1p=1 最大操作范围标记出来。


  显然,在 qqq 不为端点时,每次操作都有段不变的区间。

  图像告诉了我们,如果 qqq 操作的范围盖过了栈里最近的 qqq,那么不仅这个最近的 qqq,连同栈顶 qqq 相反的操作都是可以跳过的。

  同时根据这个性质优化后,根据栈内剩余的操作,我们总是能找到一段顺或倒序的不变区间。

  将不变区间填入最终的答案,整个算法就大体完成了。

import java.io.*;
import java.util.*;public class Main {public static void main(String[] args) { new Main().run(); }void run() {InputReader in = new InputReader(System.in);PrintWriter out = new PrintWriter(System.out);int n = in.readInt(), m = in.readInt(), top;Step[] stack = new Step[m + 1];for (top = 0; m-- > 0;) {int p = in.readInt();int q = in.readInt();if (p == 0) {while (top > 0 && stack[top].p == p) q = max(q, stack[top--].q);while (top > 1 && stack[top - 1].q <= q) top -= 2;stack[++top] = new Step(p, q);} else if (top > 0){while (top > 0 && stack[top].p == p) q = min(q, stack[top--].q);while (top > 1 && stack[top - 1].q >= q) top -= 2;stack[++top] = new Step(p, q);}}int[] ans = new int[n + 1];int a = n, l = 0, r = n - 1;for (int i = 1; i <= top; i++)if (stack[i].p == 0)while (r >= stack[i].q && l <= r) ans[r--] = a--;elsewhile (l + 1 < stack[i].q && l <= r) ans[l++] = a--;if ((top & 1) == 1)while (l <= r) ans[l++] = a--;elsewhile (l <= r) ans[r--] = a--;for (int i = 0; i < n; i++) {out.print(ans[i]);out.print(' ');}out.flush();}int max(int a, int b) { return a > b ? a : b; }int min(int a, int b) { return a < b ? a : b; }class Step {int p, q;Step(int p, int q) {this.p = p;this.q = q;}}class InputReader {BufferedReader reader;StringTokenizer token;InputReader(InputStream in) {this.reader = new BufferedReader(new InputStreamReader(in));}String read() {while (token == null || !token.hasMoreTokens()) {try {token = new StringTokenizer(reader.readLine());} catch (IOException e) {e.printStackTrace();}}return token.nextToken();}int readInt() { return Integer.parseInt(read()); }}
}

Chtholly Tree


  未加限定的珂朵莉树 (ChthollyTree\mathrm{Chtholly Tree}ChthollyTree),就是红黑树上建值域线段树,在随机构造的数据下期望复杂度为 O(nlog⁡log⁡n)O(n \log \log n)O(nloglogn),

  但 Java\mathrm{Java}Java 实现起来非常痛苦,于是 planB\mathrm{plan\ B}plan B,改用链表实现,

  其在随机构造的数据下期望复杂度为 O(nlog⁡n)O(n \log n)O(nlogn)。

  珂朵莉树的策略就是将值域相同的区间合并成一个节点,

  对于任意 [L,R][L,R][L,R] 上的操作,我们都能转换成珂朵莉树 merge(split(L),split(R+1))\mathrm{merge(split(L), split(R+1))}merge(split(L),split(R+1)) 上的操作。

  这里其实是珂朵莉链表而不是树

  举个具体且形象的例子对我来说还是太难了,

  兄弟们自己找篇博客参考一下吧。

  虽然捏个踢烂珂朵莉树的数据很简单,

  但就蓝桥的难度而言,

  出题人见没见过还是个问题。

import java.io.*;
import java.util.*;public class Main {public static void main(String[] args) { new Main().run(); }void run() {InputReader in = new InputReader(System.in);int n = in.readInt(), m = in.readInt();Node[] root = new Node[n + 1];int[] P = new int[n + 1];Range lower, temp, now;lower = now = new Range(0);for (int i = 1; i <= n; i++) {now = now.next = new Range(i);root[i] = build(1, n, i);}now.next = new Range(n + 1);while (m-- > 0) {int p = in.readInt();int L = in.readInt();int R = n;if (p == 0) {R = L;L = 1;}now = lower;while (now.next.L <= L) now = now.next;if (L > now.L) {root[L] = split(root[now.L], L - now.L, P[now.L]);now = now.next = new Range(L, now.next);}temp = now;Node pq = null;while (now.L <= R) {if (now.next.L > R + 1) root[R + 1] = split(root[now.L], R + 1 - now.L, P[R + 1] = P[now.L]);pq = merge(pq, root[now.L]);now = now.next;}if (now.L == R + 1) temp.next = now;else temp.next = new Range(R + 1, now);root[L] = pq;P[L] = p;}StringBuilder ans = new StringBuilder();while ((lower = lower.next).L <= n)buildAns(ans, root[lower.L], 1, n, P[lower.L]);System.out.println(ans);}Node split(Node tree, int k, int p) {if (tree == null) return null;Node split= new Node(0);if (p == 0) {int K = K(tree.right);if (k <= K) {if (k != K) split.right = split(tree.right, k, p);split.left = tree.left;tree.left = null;} else split.left = split(tree.left, k - K, p);} else {int K = K(tree.left);if (k <= K) {if (k != K) split.left = split(tree.left, k, p);split.right = tree.right;tree.right = null;} else split.right = split(tree.right, k - K, p);}split.k = tree.k - k;tree.k = k;return split;}Node merge(Node tree1, Node tree2) {if (tree1 == null) return tree2;if (tree2 != null){tree1.k += K(tree2);tree1.left = merge(tree1.left, tree2.left);tree1.right = merge(tree1.right, tree2.right);}return tree1;}Node build(int L, int R, int k) {if (L == R) return new Node(1);Node node = new Node(1);int mid = L + R >> 1;if (k <= mid) node.left = build(L, mid, k);else node.right = build(mid + 1, R, k);return node;}void buildAns(StringBuilder builder, Node root, int L, int R, int p) {if (root == null) return;if (L == R) builder.append(L).append(' ');else {int mid = L + R >> 1;if (p == 0) {buildAns(builder, root.right, mid + 1, R, p);buildAns(builder, root.left, L, mid, p);} else {buildAns(builder, root.left, L, mid, p);buildAns(builder, root.right, mid + 1, R, p);}}}int K(Node node) { return node == null ? 0 : node.k; }class Range {int L;Range next;Range(int L) { this(L, null); }Range(int L, Range next) {this.L = L;this.next = next;}}class Node {int k = 1;Node left, right;Node(int k) { this.k = k; }}class InputReader {BufferedReader reader;StringTokenizer token;InputReader(InputStream in) { this.reader = new BufferedReader(new InputStreamReader(in)); }String read() {while (token == null || !token.hasMoreTokens()) {try {token = new StringTokenizer(reader.readLine());} catch (IOException e) {e.printStackTrace();}}return token.nextToken();}int readInt() { return Integer.parseInt(this.read()); }}
}

#J 分果果

时间限制: 10.0s10.0\mathrm s10.0s 内存限制: 512.0MB512.0\mathrm{MB}512.0MB 本题总分:252525 分


问题描述

  小蓝要在自己的生日宴会上将 nnn 包糖果分给 mmm 个小朋友。每包糖果都要分出去,每个小朋友至少要分一包,也可以分多包。
  小蓝已经提前将糖果准备好了,为了在宴会当天能把糖果分得更平均一些,小蓝要先计算好分配方案。
  小蓝将糖果从 111 到 nnn 编号,第 iii 包糖果重 wiw_iwi​。小朋友从 111 到 mmm 编号。每个小朋友只能分到编号连续的糖果。小蓝想了很久没想出合适的分配方案使得每个小朋友分到的糖果差不多重。因此需要你帮他一起想办法。为了更好的分配糖果,他可以再买一些糖果,让某一些编号的糖果有两份。当某个编号的糖果有两份时,一个小朋友最多只能分其中的一份。
  请找一个方案,使得小朋友分到的糖果的最大重量和最小重量的差最小,请输出这个差。
  例如,小蓝现在有 555 包糖果,重量分别为 6,1,2,7,96, 1, 2, 7, 96,1,2,7,9,如果小蓝要分给两个小朋友,则他可以将所有糖果再买一份,两个小朋友都分到 111 至 555 包糖果,重量都是 252525,差为 000。
  再如,小蓝现在有 555 包糖果,重量分别为 6,1,2,7,96, 1, 2, 7, 96,1,2,7,9,如果小蓝要分给三个小朋友,则他可以将第 333 包糖果再买一份,第一个小朋友分 111 至 333 包,第二个小朋友分 333 至 444 包,第三个小朋友分第 555 包,每个小朋友分到的重量都是 999,差为 000。
  再如,小蓝现在有 555 包糖果,重量分别为 6,1,2,7,96, 1, 2, 7, 96,1,2,7,9,如果小蓝要分给四个小朋友,则他可以将第 333 包和第 555 包糖果再买一份,仍然可以每个小朋友分到的重量都是 999,差为 000。
  再如,小蓝现在有 555 包糖果,重量分别为 6,1,2,7,96, 1, 2, 7, 96,1,2,7,9,如果小蓝要分给五个小朋友,则他可以将第 444 包和第 555 包糖果再买一份,第一个小朋友分第 111 至 222 包重量为 777,第二个小朋友分第 333 至 444 包重量为 999,第三个小朋友分第 444 包重量为 777,第四个和第五个小朋友都分第 555 包重量为 999。差为 222。


输入格式

  输入第一行包含两个整数 nnn 和 mmm,分别表示糖果包数和小朋友数量。
  第二行包含 nnn 个整数 w1,w2,⋅⋅⋅,wnw_1, w_2, · · · , w_nw1​,w2​,⋅⋅⋅,wn​,表示每包糖果的重量。


输出格式

  输出一个整数,表示在最优情况下小朋友分到的糖果的最大重量和最小重量的差。


测试样例1

Input:
5 2
6 1 2 7 9Output:
0

测试样例2

Input:
5 5
6 1 2 7 9Output:
2

评测用例规模与约定

  对于 303030% 的评测用例,1≤n≤101 \leq n \leq 101≤n≤10,1≤m≤101 \leq m \leq 101≤m≤10,1≤wi≤101 \leq w_i \leq 101≤wi​≤10;
  对于 606060% 的评测用例,1≤n≤301 \leq n \leq 301≤n≤30,1≤m≤201 \leq m \leq 201≤m≤20,1≤wi≤301 \leq w_i \leq 301≤wi​≤30;
  对于所有评测用例,1≤n≤1001 \leq n \leq 1001≤n≤100,1≤m≤501 \leq m \leq 501≤m≤50,1≤wi≤1001 \leq w_i \leq 1001≤wi​≤100。在评测数据中,wiw_iwi​ 随机生成,在某个区间均匀分布。


动态规划


  可以看到,答案与区间完全划分、区间最大最小和相关,

  但是单单将这几个信息糅杂成状态,似乎很能使最终的结果满足最优性。

  不过区间最小和显然有界,其上界为 m2∑i=1nwi\frac{m}{2}\sum_{i=1}^nw_i2m​∑i=1n​wi​,这时我们设 fi,j,kf_{i,j,k}fi,j,k​ 为前 jjj 个糖果,最后一次使用两颗在 kkk,划分为 iii 个区间的和尽可能小时且不小于我们设计的最小值时,最大为多少,枚举最小值 minminmin,一个可能的答案就是 fm,n,n−minf_{m,n,n} - minfm,n,n​−min。

  于是有三种转移:

  fi,j,k⟵fi,j,k−1f_{i,j,k} \longleftarrow f_{i,j,k-1}fi,j,k​⟵fi,j,k−1​
  fi,j,k⟵min⁡max⁡(fi−1,j′,j′,∑i′=j′+1jwi′)f_{i,j,k} \stackrel{\min}\longleftarrow \max (f_{i-1,j',j'},\sum_{i'=j'+1}^jw_{i'})fi,j,k​⟵min​max(fi−1,j′,j′​,∑i′=j′+1j​wi′​),j′≤k≤jj' \leq k \leq jj′≤k≤j
  fi,j,k⟵min⁡max⁡(fi−1,k′,j′,∑i′=j′+1jwi′)f_{i,j,k} \stackrel{\min}\longleftarrow \max (f_{i-1,k',j'},\sum_{i'=j'+1}^jw_{i'})fi,j,k​⟵min​max(fi−1,k′,j′​,∑i′=j′+1j​wi′​),j′≤k′≤k≤jj' \leq k' \leq k \leq jj′≤k′≤k≤j

  第一种转移意味着我们不关心最后使用两颗糖的位置在哪,简化了后两种转移且不影响结果的最优性。

  第二、三种转移表示寻找一个最优的相交区间和一个最优的不相交区间。

  但朴素的去转移其复杂度分别为 O(1)O(1)O(1)、O(n)O(n)O(n)、O(n2)O(n^2)O(n2),整个动态规划的复杂度在 O(m2∑i=1nwi×m×n2×n2)=O(n4∑i=1nwi)O(\frac{m}{2}\sum_{i=1}^nw_i×m×n^2×n^2) = O(n^4\sum_{i=1}^nw_i)O(2m​∑i=1n​wi​×m×n2×n2)=O(n4∑i=1n​wi​),

  铁超时,

  于是考虑优化,

  对于第二类转移,容易发现 F(x)=max⁡(fi−1,x,x,∑i′=j′+1jwi′)F(x) =\max (f_{i-1,x,x},\sum_{i'=j'+1}^jw_{i'})F(x)=max(fi−1,x,x​,∑i′=j′+1j​wi′​) 为单谷函数,维护这个 xxx,每次循环都检查下最优性即可。

  对于第三类转移,容易发现 fi,j,k⟵fi,j,k−1f_{i,j,k} \longleftarrow f_{i,j,k-1}fi,j,k​⟵fi,j,k−1​ 时,fi,j,k≤max⁡(fi−1,k′,j′,∑i′=j′+1jwi′)f_{i,j,k} \leq \max (f_{i-1,k',j'},\sum_{i'=j'+1}^jw_{i'})fi,j,k​≤max(fi−1,k′,j′​,∑i′=j′+1j​wi′​),j′≤k′<kj' \leq k' < kj′≤k′<k,即 fi,j,kf_{i,j,k}fi,j,k​ 已经考虑第三种转移 k′≠kk' \neq kk′​=k 的所有情况,因此将第三种转移简化为 fi,j,k⟵min⁡max⁡(fi−1,k,j′,∑i′=j′+1jwi′)f_{i,j,k} \stackrel{\min}\longleftarrow \max (f_{i-1,k,j'},\sum_{i'=j'+1}^jw_{i'})fi,j,k​⟵min​max(fi−1,k,j′​,∑i′=j′+1j​wi′​),j′≤kj' \leq kj′≤k 且 j′j'j′ 为满足 ∑i′=j′+1jwi′≥min\sum_{i'=j'+1}^jw_{i'} \ge min∑i′=j′+1j​wi′​≥min 的最大值,因为 F(x)=fi,j,xF(x) = f_{i,j,x}F(x)=fi,j,x​ 单调不上升且 F(x)=∑i=xjwiF(x) = \sum_{i=x}^jw_{i}F(x)=∑i=xj​wi​ 单调递减,自然 j′j'j′ 尽可能的大更优,同样的使用一个变量,每次循环都检查下最优性即可。

  优化后的复杂度在 O(n2∑i=1nwi)O(n^2\sum_{i=1}^nw_i)O(n2∑i=1n​wi​)。

import java.io.*;
import java.util.*;public class Main {public static void main(String[] args) { new Main().run(); }int INF = 0x3F3F3F3F;void run() {InputReader in = new InputReader(System.in);int n = in.readInt(), m = in.readInt(), ans = INF;int[][][] dp = new int[m + 1][n + 1][n + 1];int[] S = new int[n + 1];for (int i = 1; i <= n; i++)S[i] = S[i - 1] + in.readInt();for (int i = 0; i <= m; i++)for (int j = 0; j <= n; j++)for (int k = 0; k <= j; k++) dp[i][j][k] = INF;dp[0][0][0] = 0;for (int min = S[n] * 2 / m; min > 0; min--) {for (int i = 1; i <= m; i++)for (int j = 1; j <= n; j++) {int trans2 = 0, trans3 = 0;for (int k = 1; k <= j; k++) {dp[i][j][k] = dp[i][j][k - 1];while (trans2 < k && S[j] - S[trans2 + 1] >= min &&max(dp[i - 1][trans2 + 1][trans2 + 1], S[j] - S[trans2 + 1]) <= max(dp[i - 1][trans2][trans2], S[j] - S[trans2])) trans2++;if (S[j] - S[trans2] >= min)dp[i][j][k] = min(dp[i][j][k], max(dp[i - 1][trans2][trans2], S[j] - S[trans2]));while (trans3 < k && S[j] - S[trans3 + 1] >= min &&max(dp[i - 1][k][trans3 + 1], S[j] - S[trans3 + 1]) <= max(dp[i - 1][k][trans3 + 1], S[j] - S[trans3])) trans3++;if (S[j] - S[trans3] >= min)dp[i][j][k] = min(dp[i][j][k], max(dp[i - 1][k][trans3], S[j] - S[trans3]));}}ans = min(ans, dp[m][n][n] - min);}System.out.println(ans);}int max(int arg1, int arg2) { return arg1 > arg2 ? arg1 : arg2; }int min(int arg1, int arg2) { return arg1 < arg2 ? arg1 : arg2; }class InputReader {BufferedReader reader;StringTokenizer token;InputReader(InputStream in) {this.reader = new BufferedReader(new InputStreamReader(in));}String read() {while (token == null || !token.hasMoreTokens()) {try {token = new StringTokenizer(reader.readLine());} catch (IOException e) {e.printStackTrace();}}return token.nextToken();}int readInt() { return Integer.parseInt(read()); }}
}

Fin

第十二届蓝桥杯 2021年省赛真题 (Java 大学A组) 第一场相关推荐

  1. 第十二届蓝桥杯 2021年省赛真题 (Java 大学B组) 第一场

    蓝桥杯 2021年省赛真题 (Java 大学B组 ) #A ASC #B 卡片 朴素解法 弯道超车 #C 直线 直线方程集合 分式消除误差 平面几何 #D 货物摆放 暴力搜索 缩放质因子 #E 路径 ...

  2. 第十二届蓝桥杯 2021年国赛真题 (Java 大学A组)

    蓝桥杯 2021年国赛真题(Java 大学 A 组 ) #A 纯质数 按序枚举 按位枚举 #B 完全日期 朴素解法 朴素改进 #C 最小权值 动态规划 #D 覆盖 变种八皇后 状压 DP #E 123 ...

  3. 第十二届蓝桥杯 2021年省赛真题 (Java 大学C组) 时间显示

    #F 时间显示 时间限制: 1.0s 内存限制: 512.0MB 本题总分: 15 分 问题描述 小蓝要和朋友合作开发一个时间显示的网站.在服务器上,朋友已经获取了当前的时间,用一个整数表示,值为从 ...

  4. 第十二届蓝桥杯 2021年省赛真题 (C/C++ 大学A组) 第一场

    蓝桥杯 2021年省赛真题 (C/C++ 大学A组 ) #A 卡片 #B 直线 #C 货物摆放 #D 路径 #E 回路计数 #F 砝码称重 背包 DP #G 异或数列 #H 左孩子右兄弟 #I 括号序 ...

  5. 第十二届蓝桥杯 2021年省赛真题 (C/C++ 大学B组)

    蓝桥杯 2021年省赛真题 (C/C++ 大学B组 ) #A 空间 #B 卡片 #C 直线 #D 货物摆放 #E 路径 #F 时间显示 #G 砝码称重 背包 DP #H 杨辉三角形 #I 双向排序 贪 ...

  6. 第十二届蓝桥杯 2021年国赛真题 (C/C++ 大学A组)

    蓝桥杯 2021年国赛真题(C/C++ 大学 A 组 ) #A 纯质数 #B 完全日期 #C 最小权值 #D 覆盖 #E 123 #F 异或变换 #G 冰山 #H 翻转括号序列 #I 异或三角 #J ...

  7. 蓝桥杯 2018年省赛真题 (Java 大学C组)

    蓝桥杯 2018 年省赛真题(Java 大学 C 组 ) #1 哪天返回 #2 猴子分香蕉 #3 字母阵列 #4 第几个幸运数 #5 书号验证 #6 打印大X #7 缩位求和 #8 等腰三角形 #9 ...

  8. 蓝桥杯 2019年省赛真题 (Java 大学B组)

    蓝桥杯 2019 年省赛真题(Java 大学 B 组 ) #A 组队 #B 不同子串 #C 数列求值 #D 数的分解 #E 迷宫 #F 特别数的和 #G 外卖店优先级 #H 人物相关性分析 #I 后缀 ...

  9. 蓝桥杯|2021第十二届蓝桥杯第二次模拟赛真题与解答[Java]

    记录2021年第十二届蓝桥杯第二次模拟赛真题与解题,部分答案来自网络.个人记录,菜得很. 目录 填空题 一 二 三 四 五 编程题 六 七 八 九 十 填空题 一 问题描述 请问在 1 到 2020 ...

最新文章

  1. Sublime Text 3 史上最性感的编辑器
  2. Package 'xxxx' is not installed, so not removed
  3. Node.js学习之路24——Express框架的app对象
  4. qt for android 图片可拉伸,qt实现九宫格布局,图片拉伸
  5. Fedora 17 Beta 版发布
  6. Hoshin Kanri在丰田的应用
  7. linux监控http连接数,zabbix监控linux tcp连接数
  8. docker本地构建kerberos单机环境
  9. NLP语言资源 | 汽车、金融等9大领域预训练词向量与依存、拼音等4类特殊向量开放...
  10. (入门)keystonejs入门教程之环境搭建
  11. Qt之QTreeWidget增删节点
  12. Unity线性空间UI制作方面总结
  13. accept搭配用法_accept for的用法与搭配
  14. RGB 和 CMYK 相互转换
  15. Snapde和Excel、PowerPivot、WPS打开超大CSV文件性能比较
  16. 九:以理论结合实践方式梳理前端 React 框架 ——— 简述中间件
  17. Anchor-based 与 Anchor-free
  18. MATLAB 基础知识 数据类型 表 添加和删除表行
  19. ② kubeadm快速部署Kubernetes集群
  20. C#调用BarTender打印

热门文章

  1. Android permission denied原因归纳和解决办法
  2. 在WhatsApp中如何发起群发?
  3. GPS纠偏算法,适用于google,高德体系的地图
  4. web前端开发零基础入门教程
  5. 二叉树交换左右子树的递归与非递归算法
  6. SpringBoot整合Prometheus实现业务指标上报
  7. python调用python脚本
  8. 达人评测 RTX3060和RX 6600M选哪个好
  9. H264解码器源码(vc6版)H264Decoder_vc6.rar
  10. 计算机能力测试power,PowerMAX(电脑拷机测试软件)