T1

100%

读入字符串 SS,枚举字符串 SS 的第 ii 位,如果 S[i]S[i] 等于 ?,那么将 S[i]S[i] 修改为 !

全部修改完后再输出 SS 即可。

时间复杂度 O(n)O(n)

T2

100%

两重循环:

  • 第一层循环枚举 i=2ni=2\sim n
  • 第二层循环枚举 j=1i1j=1\sim i-1,如果 h[j]>h[i]h[j]>h[i],将 h[j]h[j]h[i]h[i] 进行交换,并使用 break\text{break} 语句结束本次循环。

时间复杂度 O(n2)O(n^2)

T3

50%

维护当前等级 xx 和当前经验 yy,初始时 x=1,y=0x=1,y=0

用一个循环枚举刷题过程:

  • 先增加 xx 点经验:y+=xy+=x
  • 判断当前经验是否能升级,如果 yk×x2y\geq k\times x^2 说明能升级,那么消耗 k×x2k\times x^2 点经验升级:y=k×x2y-=k\times x^2x++x++

注意消耗经验和升级这两条语句的顺序。

时间复杂度 O(n)O(n)

100%

当你为 xx00 经验时,你刷 k×xk\times x 道题正好获得 k×x2k\times x^2 经验,升到 x+1x+100 经验。

所以我们维护剩余题数 nownow,初始 now=nnow=n,用一个 while\text{while} 循环来模拟这个过程:

  • 如果 nowk×xnow\geq k\times x,那么我们刷 k×xk\times x 道题然后升一级:now=k×xnow-=k\times xx++x++
  • 否则我们刷完这 nownow 道题也不能升级:y+=now×xy+=now\times xnow=0now=0
  • nownow 变为 00 时结束循环,所以 while\text{while} 的循环条件为 now>0now>0

升到 vv 级需要刷 $k \times (1+2+3+\dots+(v-1))= k \times \frac{v\times (v-1)}{2}$ 道题,因此最终等级不会超过 2×n2\times\sqrt{n},也就是说循环最多运行 2×n2\times \sqrt{n} 次。

时间复杂度 O(n)O(\sqrt{n})

T4

40%

维护二维数组 a[i][j]a[i][j] 表示位于第 ii 行第 jj 列的同学的编号,初始 a[i][j]=(i1)×m+ja[i][j]=(i-1)\times m+j

按顺序执行每条训练指令,对于第 ii 条训练指令:

  • 11 类指令,用一个循环枚举 i=1mi=1\sim m,交换 a[x][i]a[x][i]a[y][i]a[y][i]
  • 22 类指令,用一个循环枚举 i=1ni=1\sim n,交换 a[i][x]a[i][x]a[i][y]a[i][y]
  • 33 类指令,输出 a[x][y]a[x][y]

时间复杂度 O(nm+q(n+m))O(nm+q(n+m))

60%

对于测试点#5~6,因为不存在 22 类指令,所以每一行的内部不发生交换,交换只发生在行与行之间。

维护数组 r[i]r[i] 表示现在位于方阵第 ii 行的同学初始时位于方阵的哪一行,初始 r[i]=ir[i]=i

按顺序执行每条训练指令,对于第 ii 条训练指令:

  • 11 类指令,交换 r[x]r[x]r[y]r[y]
  • 33 类指令,现在位于第 xx 行第 yy 列的同学,初始时位于方阵的第 r[x]r[x] 行第 yy 列,输出 (r[x]1)×m+y(r[x]-1)\times m+y

时间复杂度 O(n+q)O(n+q)

100%

行的交换与列的交换是互相独立的:一个同学最终位于哪一行只和 11 类指令有关,最终位于哪一列只和 22 类指令有关。

维护数组 r[i]r[i] 表示现在位于方阵第 ii 行的同学初始时位于方阵的哪一行,数组 c[i]c[i] 表示现在位于方阵第 ii 列的同学初始时位于方阵的哪一列,初始 r[i]=i,c[i]=ir[i]=i,c[i]=i

按顺序执行每条训练指令,对于第 ii 条训练指令:

  • 11 类指令,交换 r[x]r[x]r[y]r[y]
  • 22 类指令,交换 c[x]c[x]c[y]c[y]
  • 33 类指令,现在位于第 xx 行第 yy 列的同学,初始时位于方阵的第 r[x]r[x] 行第 c[y]c[y] 列,输出 (r[x]1)×m+c[y](r[x]-1)\times m+c[y]

时间复杂度 O(n+m+q)O(n+m+q)

T5

20%

k=2k=2,合法密码即为相邻位不同的密码。

那么合法密码仅有两种:①形如 121212121212\dots,即奇数位为 11 偶数位为 22;②形如 212121212121\dots,即奇数位为 22 偶数位为 11

对于第一种情况,奇数位只能是 1100,偶数位只能是 2200。枚举 SS 的每一位进行判断,都满足则答案增加 11

对于第二种情况,奇数位只能是 2200,偶数位只能是 1100。枚举 SS 的每一位进行判断,都满足则答案增加 11

时间复杂度 O(n)O(n)

60%

定义 dp[i][j][len]dp[i][j][len] 表示只考虑前 ii 位,其中的最后一段为 lenlenjj 的合法密码的数量。

  • 如果 S10S_1\neq 0,初值为 dp[1][S1][1]=1dp[1][S_1][1]=1
  • 否则枚举 j=1kj=1\sim k,初值为 dp[1][j][1]=1dp[1][j][1]=1

考虑当 i>1i>1 时的转移:

  • 第一重循环枚举第 i1i-1 位的数字 y=1ky=1\sim k
  • 第二重循环枚举前 i1i-1 位的最后一段的长度 len=1k1len=1\sim k-1
  • 如果 Si=0S_i=0 则第三重循环枚举第 ii 位的数字 x=1kx=1\sim k,否则第 ii 位的数字 x=Six=S_i
  • 如果 xyx\neq y,那么此时前 ii 位数字的最后一段为 11xx,转移为 dp[i][x][1]+=dp[i1][y][len]dp[i][x][1]+=dp[i-1][y][len]
  • 如果 x=yx=ylen<k1len<k-1,那么此时前 ii 位数字的最后一段为 len+1len+1xx,转移为 dp[i][x][len+1]+=dp[i1][x][len]dp[i][x][len+1]+=dp[i-1][x][len]

时间复杂度 O(nk3)O(nk^3)

100%

观察第二部分,我们发现:

  • $dp[i][x][1]=\sum_{y\neq x}\sum_{z=0}^{k-1}dp[i-1][y][z]$;
  • 对于 len>1len>1dp[i][x][len]=dp[i1][x][len1]dp[i][x][len]=dp[i-1][x][len-1]

其中 dp[i][x][1]dp[i][x][1] 的部分是复杂度的瓶颈。

定义 f[i][j]f[i][j] 表示只考虑前 ii 位,第 ii 位为 jj 的合法密码的总数量。f[i][j]=len=1k1dp[i][j][len]f[i][j]=\sum_{len=1}^{k-1} dp[i][j][len]

定义 g[i]g[i] 表示只考虑前 ii 位,合法密码的总数量。g[i]=x=1kf[i][x]g[i]=\sum_{x=1}^k f[i][x]

$dp[i][x][1]=\sum_{y\neq x}\sum_{z=0}^{k-1}dp[i-1][y][z]=g[i-1]-f[i-1][x]$,这样就可以把单个状态转移的复杂度降低到 O(1)O(1)

时间复杂度 O(nk2)O(nk^2)

可以使用滚动数组的技巧来降低空间复杂度。

T6

10%

将学生按照分数从大到小排序,然后分为四类,用四个数组分别处理:

  • 语文数学都好的同学称为 AA 类学生,用数组 AA 储存他们的分数,计算其中分数前 ii 大的学生的总分 sA[i]=A[1]+A[2]++A[i]sA[i]=A[1]+A[2]+\dots+A[i]
  • 只有语文好的同学称为 BB 类学生,用数组 BB 储存他们的分数,计算其中分数前 ii 大的学生的总分 sB[i]=B[1]+B[2]++B[i]sB[i]=B[1]+B[2]+\dots+B[i]
  • 只有数学好的同学称为 CC 类学生,用数组 CC 储存他们的分数,计算其中分数前 ii 大的学生的总分 sC[i]=C[1]+C[2]++C[i]sC[i]=C[1]+C[2]+\dots+C[i]
  • 语文数学都不好的同学称为 DD 类学生,用数组 DD 储存他们的分数,计算其中分数前 ii 大的学生的总分 sD[i]=D[1]+D[2]++D[i]sD[i]=D[1]+D[2]+\dots+D[i]

四重循环分别枚举:

  • AA 类学生选 nAnA 名,BB 类学生选 nBnB 名,CC 类学生选 nCnC 名,DD 类学生选 nDnD 名;
  • 然后判断,如果满足 nA+nB+nC+nD=mnA+nB+nC+nD=mnA+nBk1nA+nB\geq k_1nA+nCk2nA+nC\geq k_2
  • 那么更新答案 ans=max(ans,sA[nA]+sB[nB]+sC[nC]+sD[nD])ans=\max(ans,sA[nA]+sB[nB]+sC[nC]+sD[nD])

时间复杂度 O(n4)O(n^4)

40%

在第一部分的基础上,只枚举 nA,nB,nCnA,nB,nC

  • 要求 nA+nB+nCmnA+nB+nC\leq m,此时 nD=mnAnBnCnD=m-nA-nB-nC
  • 然后判断,如果满足 nA+nBk1nA+nB\geq k_1nA+nCk2nA+nC\geq k_2
  • 那么更新答案 ans=max(ans,sA[nA]+sB[nB]+sC[nC]+sD[nD])ans=\max(ans,sA[nA]+sB[nB]+sC[nC]+sD[nD])

时间复杂度 O(n3)O(n^3)

60%

对于测试点#5~6,因为 l2>r1l_2>r_1,所以不存在 AA 类学生。

因此 BB 类学生至少要选 k1k_1 名,CC 类学生至少要选 k2k_2 名。

  • 先选分数最大的 k1k_1BB 类学生和 k2k_2CC 类学生,要求 k1+k2mk_1+k_2\leq m
  • 从剩下的学生中选出分数最大的 mk1k2m-k_1-k_2 名:将剩余的 BB 类和 CC 类学生,以及所有 DD 类学生,一起按分数从大到小排序,选其中分数最大的 mk1k2m−k_1−k_2 名。

时间复杂度 O(nlog(n))O(n\log(n))

结合第二部分可以拿到 60%60\% 的分数。

100%

在第三部分的基础上,从小到大枚举选择了 nAnAAA 类学生:

  • 如果 nA<k1nA<k_1 那么 BB 类学生中必选分数最大的 k1nAk_1-nA 名,要求 BB 类学生至少有 k1nAk_1-nA 名;
  • 如果 nA<k2nA<k_2 那么 CC 类学生中必选分数最大的 k2nAk_2-nA 名,要求 CC 类学生至少有 k2nAk_2-nA 名;
  • 要求 k1+k2nAmk_1+k_2-nA\leq m
  • 剩余学生中选分数最大的 m(k1+k2nA)m-(k_1+k_2-nA) 名,使用对顶堆的技巧来处理这个部分:
    • 用小根堆 qLqL 和大根堆 qRqR 来储存这些学生,分数最大的那部分储存在 qLqL 中,分数最小的那部分储存在 qRqR 中;
    • 在最开始把所有 CC 类学生放入 qLqL
    • 因为 nAnA 是从小到大枚举,所以 k1nAk_1-nAk2nAk_2-nA 都是变小的,每次将不再必选的 BB 类或 CC 类学生放入对顶堆:如果分数大于 qLqL 中分数最小的学生那么放入 qLqL,否则放入 qRqR
    • 然后通过将 qLqL 中分数最小的学生取出放到 qRqR 中,或将 qRqR 中分数最大的学生取出放到 qLqL 中,将 qLqL 中元素的数量调整为 m(k1+k2nA)m-(k_1+k_2-nA),代表选剩余学生中分数最大的 m(k1+k2nA)m-(k_1+k_2-nA) 名;
    • 过程中维护 qLqL 中的元素之和 sQsQ;
  • 更新答案 ans=max(ans,sA[nA]+sB[k1nA]+sC[k2nA]+sQ)ans=\max(ans,sA[nA]+sB[k_1-nA]+sC[k_2-nA]+sQ)

时间复杂度 O(nlog(n))O(n\log(n))

0 comments

No comments so far...