GPLT 团体程序设计天梯赛 2023年 - 正式赛 赛后复盘 附思路与代码注释

前言:2023年的天梯赛难度是近年来最难的,L1有些难度、L2难度大增、L3近年最难。短短3小时内,该如何获得尽可能高的分?这里提供了一系列技巧,重点会加粗

参考资料:2023年天梯赛的国家奖切线是250/220/175;如果采用近两年的新切线算法(即根据175分及以上的1:3:6人数比例颁奖),国家奖切线是226/193/175。

接下来直接上技巧与代码,全文共23386字,配合右边的目录阅读体验更佳~

如果这篇文章被自动设置为VIP可见或者付费,请尽快联系我。

L1-基础级(100分)

题目偏难,这一年挖坑的题变成2道了(参考L1-6和L1-7),很容易写错。

但L1部分基本上还是涵盖了近年来L1的所有考点:

简单输出、顺序语句、分支语句、循环语句、字符串处理、较复杂模拟。

建议学习set、unordered_set、map、unordered_map,对部分题目有显著效果。

L1必有至少一道题目挖坑。(例如审题、一些边界问题、暴力做法超时等)

L1的绝大多数题目,用任何语言写出正解不会超时。

C++选手的优秀手速(自己可以尝试训练到这个标准,可以给L2和L3多出很多做题时间):

获奖过天梯赛的选手:达到95分:30分钟。达到100分:40分钟。

未获奖过天梯赛的选手,在50-60分钟内得到90-95分就很不错;熟练后可按上述要求练习手速。

L1-1 最好的文档(5分)

原题链接:L1-089 最好的文档 - 团体程序设计天梯赛-练习集

思路:直接输出字符串即可。

提示:这道题可以存你的模板/头文件,方便直接复制。

C++代码:L1-089 最好的文档_好代码本身就是最好的文档-CSDN博客

Python代码:

from heapq import heappush,heappop #优先队列
from bisect import bisect,bisect_left #二分,类似C++的lower_bound
from math import sqrt,ceil,floor #开根号,向上取整,向下取整
from collections import deque #双端队列,C++也有
import sys #这个模块很有用
import time #time.time()相减可以算运行时间,在蓝桥杯赛制下有用 检测是否超时
sys.setrecursionlimit(1000010) #手动设置递归深度,解除递归限制 默认递归深度999
sys.set_int_max_str_digits(1000010) #设置数字最大位数(更高的高精度)
inpu = sys.stdin.readline #快读,字符串末尾带换行,用strip()方法可以去换行
prin = sys.stdout.write #快写,不会自带换行,要手动换行
#上面是模板,可以复制到其他题目
print("Good code is its own best documentation.")

#C++模板,记得在PTA上的Python3语言环境同时按下Ctrl+/,解除注释,然后切换到C++语言
#天梯赛可以用不同的语言交题目(例如一道题用Python3,另一道题用C++)
# #include<bits/stdc++.h>
# using namespace std;
# typedef long long ll;
# #define append push_back
# #define print printf
# int main()
# {
#     ios::sync_with_stdio(false);
#     cin.tie(0);
#     cout.tie(0);
#     return 0;
# }

L1-2 什么是机器学习(5分)

原题链接:L1-090 什么是机器学习 - 团体程序设计天梯赛-练习集

思路:直接分行输出4种结果即可。

提示:无。

C++代码:L1-090 什么是机器学习-CSDN博客

Python代码:

from collections import deque
from math import sqrt,ceil,floor
import sys
sys.setrecursionlimit(1000010)
sys.set_int_max_str_digits(1000010)
inpu = sys.stdin.readline
prin = sys.stdout.write

a,b = map(int,input().split()) #用map来将分割后字符串的存到对应的数字里面
print(a+b-16)
print(a+b-3)
print(a+b-1)
print(a+b)

L1-3 程序员买包子(10分)

原题链接:L1-091 程序员买包子 - 团体程序设计天梯赛-练习集

思路:用if-else语句判断每个情况,题目的输出格式已经提示了。

提示:无。

C++代码:L1-091 程序员买包子 分数 10 - Frodnx - 博客园

Python代码:

from heapq import heappush,heappop
from bisect import bisect,bisect_left
from math import sqrt,ceil,floor
from collections import deque
import sys
import time
sys.setrecursionlimit(1000010)
sys.set_int_max_str_digits(1000010)
inpu = sys.stdin.readline
prin = sys.stdout.write

nn,x,mm,kk = input().split()
n,m,k = int(nn),int(mm),int(kk)
#输出字符串用%s,和C语言一样
if k == n:
    print("mei you mai %s de"%x)
elif k == m:
    print("kan dao le mai %s de"%x)
else:
    print("wang le zhao mai %s de"%x)


L1-4 进化论(10分)

原题链接:​​​​​​​L1-092 进化论 - 团体程序设计天梯赛-练习集

思路:用if-else语句判断每个情况,题目的输出格式已经提示了。

提示:无。

C++代码:pta L1-092 进化论_l1-092python-CSDN博客

Python代码:

from collections import deque
from math import sqrt,ceil,floor
import sys
sys.setrecursionlimit(1000010)
sys.set_int_max_str_digits(1000010)
inpu = sys.stdin.readline
prin = sys.stdout.write

n=int(input())
for i in range(n):
    #直接输入输出就行
    a,b,c = map(int,input().split())
    if c == a*b:
        print("Lv Yan")
    elif c == a+b:
        print("Tu Dou")
    else:
        print("zhe du shi sha ya!")

L1-5 猜帽子游戏(15分)

原题链接:​​​​​​​L1-093 猜帽子游戏 - 团体程序设计天梯赛-练习集

思路:输入正确答案后,用for循环读入每组“猜”的情况,之后根据情况输出Da Jiang!!!或者Ai Ya,建议直接从题目复制,自己手打容易打错。

提示:1.只要有一个不正确,就是Ai Ya

           2.如果所有人都弃权(即全0),也是Ai Ya

           3.只要有人猜对,且其他人弃权或无人猜错,就是Da Jiang!!!

C++代码:PTA L1-093 猜帽子游戏 (15 分)-CSDN博客

Python代码:

from heapq import heappush,heappop
from bisect import bisect,bisect_left
from math import sqrt,ceil,floor
from collections import deque
import sys
import time
sys.setrecursionlimit(1000010)
sys.set_int_max_str_digits(1000010)
inpu = sys.stdin.readline #快读
prin = sys.stdout.write #快写

#inpu是快读,不是打错了,后面题目同理
n = int(inpu())
a = list(map(int,inpu().split())) #根据读入的行转为整型列表(类似C++的数组)
m = int(inpu())
for i in range(m):
    b = list(map(int,inpu().split()))
    dui = 1 #假设所有人猜对
    f0 = 0 #非0,就是是否有人猜
    for j in range(n):
        if b[j] != 0:
            f0 = 1 #有人猜,排除所有人弃权的情况
            if b[j] != a[j]: #这里的条件嵌套于 b[j] != 0 内,即这个人不是弃权的
                dui = 0
    if dui == 1 and f0 == 1: #如果有人没弃权,猜的人全猜对,就输出大奖
        print("Da Jiang!!!")
    else:
        print("Ai Ya")


L1-6 剪切粘贴 (15分)

原题链接:​​​​​​​L1-094 剪切粘贴 - 团体程序设计天梯赛-练习集

思路:对于每个操作,有4个参数,分离字符串的起始下标,分离字符串的结束下标,要查找的两个字符串。如果能找到一种两个字符串相邻(不能有重叠)的情况,就把分离的字符串塞入第一次出现的相邻字符串之间的那个位置;否则塞入末尾。

提示:1.题目每组操作提供的下标从1开始,记得转从0开始的下标,或者进行其他特殊处理。

           2.必须先把要复制的字符串分离出来再寻找对应位置;假设有一组操作:1 3 ab c,而原字符串是abcdeabc,那么先把前面的abc分离出来,得到字符串deabc,找到的第一个位置是de后面的abc,之后字符串变成deababcc。

           3.找出来的位置不能重叠。假设有一组操作:9 10 hav ave,原字符串是 Ihaveanapple,此时不应该记录位置(因为have的hav和ave是重叠的)。正确的做法是找不到相邻的字符串,把分离的字符串塞入字符串末尾。 

           4.如果有选手使用两个字符串分开找的方法,记住一定要找到第一次出现的相邻字符串的那个位置。假设有一组操作:1 2 e f,原字符串abessfssfsesefsesfefe,则设计的算法要将分离的字符串放入第一次出现的字符串(即上述字符串加粗的位置)的中间。输入样例的最后一组操作就考虑了这个情况。

           5.C++选手请灵活使用substr和find的函数,解决L1的字符串问题非常有用!可以参考下方的文章。如果学有余力,可以学习这篇文章的其他STL字符串操作函数。Python选手也尝试掌握find方法、replace方法和切片的熟练应用。注意Python的标准str类型不能直接修改字符串的一部分(哪怕只修改一个字母也不行),只能重新切片并组合。

C++代码:PTA L1-094 剪切粘贴 (超简版——灵活运用string模板库里的函数(也就练习了半坤年))_剪切粘贴pta-CSDN博客

Python代码:

from heapq import heappush,heappop
from bisect import bisect,bisect_left
from math import sqrt,ceil,floor
from collections import deque
import sys
import time
sys.setrecursionlimit(1000010)
sys.set_int_max_str_digits(1000010)
inpu = sys.stdin.readline
prin = sys.stdout.write

a = input()
n = int(input())
for i in range(n):
    ll,rr,aa,bb = input().split() #不能直接用map转int,输入的类型不完全是int
    l,r = int(ll),int(rr) #单独转int操作
    #python的切片是左闭右开区间,截取了原字符串的[l-1,r-1]部分,下标自动转化为从0开始
    tmp = a[l-1:r]
    a = a[:l-1] + a[r:] #原字符串删去被截取的字符串
    #print(a) #调试语句 检查中间a的变化情况
    #采取分开找相邻字符串的策略 p1存储相邻字符串左边的末尾+1个位置
    #p2存储相邻字符串右边的开头位置 这样进行匹配时中间的下标就是一样的
    #例如对"there"查找the和re,p1找到"the"存储下标3,p2找到"re"存储下标3
    p1 = [] 
    p2 = []
    #基于切片的查找操作 左相邻字符串记录末尾+1(即i+len(aa))下标,右相邻字符串记录开头下标
    for i in range(len(a)):
        if a[i:i+len(aa)] == aa:
            p1.append(i+len(aa))
    for i in range(len(a)):
        if a[i:i+len(bb)] == bb:
            p2.append(i)
    pos = -1 #假设没找到
    fff = 0 #找到第一个的标志,为1直接break
    #O(n^2)暴力枚举相邻下标的过程
    for i in p1: #相当于C++的 for(auto i:p1)
        if fff == 1:
            break
        for j in p2:
            if i == j: #下标相等
                fff = 1 #找到第一个了 不需要再找
                pos = i #记录要插入的那个下标
                break
    if pos == -1: 
        a = a + tmp #没找到插入末尾
    else:
        a = a[:pos] + tmp + a[pos:]
print(a)

L1-7 分寝室 (20分)

原题链接:​​​​​​​L1-095 分寝室 - 团体程序设计天梯赛-练习集

思路:n0、n1、n是女生人数、男生人数、宿舍数。可以开一个vector表示一间宿舍可能住下的人数,用for循环枚举i从1到(每种性别总人数-1)的宿舍数量与对应的人数,就是 n0/i 或 n1/i(注意这个是人数),如果能被整除就塞入对应性别的vector。

为什么只能枚举到每种性别总人数-1?因为题目明确表示不能单人单间。之后用两层for循环暴力枚举男生和女生宿舍数的总和是否为n,如果为n取宿舍数量的差最小的那一对答案。两层for循环暴力枚举不会超时,因为据资料统计:10的5次方含有最多个约数的数,他的约数也只有128个。

提示:1.vector存的是宿舍当前住的人数。

           2.按照上述的思路,判断刚好凑满n间宿舍的代码是:

            //C++
            if (n0/i + n1/j == n)
            //Python 除号要用//才能向下取整
            if n0 // i + n1 // j == n:

           3.最后输出的是宿舍数,即for循环枚举的i,j得来的 n0/i 与 n1/j,更新答案赋值用这一个值;但判断并更新最小差的是人数差,即 i , j。记得用abs(i-j)更新人数差,因为枚举的j可能比i更小

           4.记得特判No Solution的情况。

           5.下方文章的代码与这篇文章的思路大致一样,他的方法不需要预处理,代码稍微简单一些,可以做一个参考。

C++代码:PTA L1-095 分寝室(理解题意轻松WA)_学校新建了宿舍楼,共有 n 间寝室。等待分配的学生中,有女生 n 0 位、男生 n 1 位-CSDN博客

Python代码:

from heapq import heappush,heappop
from bisect import bisect,bisect_left
from math import sqrt,ceil,floor
from collections import deque
import sys
import time
sys.setrecursionlimit(1000010)
sys.set_int_max_str_digits(1000010)
inpu = sys.stdin.readline
prin = sys.stdout.write

n0,n1,n = map(int,input().split())
#其实不用set直接用列表也可以,那这样add需要改成append
#注意男女存储的是人数
na = set()
nv = set()
#python的for循环左闭右开,不会循环到n0和n1
for i in range(1,n0):
    if n0 % i == 0:
        na.add(n0 // i) #枚举所有可能出现的人数,下同
for i in range(1,n1):
    if n1 % i == 0:
        nv.add(n1 // i)
cha = int(1e9) #取一个足够大的数初始化最小的人数差
naa,nvv = -1,-1 #-1,-1表示无解
for i in na:
    for j in nv:
        if n0 // i + n1 // j == n:
            if (abs(i-j)) <= cha: #一定要开abs,人数差不会是负数
                cha = abs(i-j) 
                naa,nvv = n0 // i,n1 // j #注意结果更新的是宿舍数
if naa == -1 and nvv == -1:
    print("No Solution")
else:
    print(naa,nvv)

L1-8 谁管谁叫爹(20分)

原题链接:​​​​​​​L1-096 谁管谁叫爹 - 团体程序设计天梯赛-练习集

思路:这题算是比较简单的L1-8,直接求的数位和,赋值到中,最后判断两个条件满足其一、都满足、都不满足的情况即可。

提示:1.这道题比L1-6和L1-7都要简单,所以如果这两道题的边界条件没有调好,可以先放下L1-6和L1-7的一小部分测试点做L1-8,等回头再补这两道题;

           2.不能直接让除以自身求出数位和,这样出现相同的情况就没法比较原先的数谁大了,可以创建一个临时变量tmp,令tmp等于,之后求

C++代码:PTA-L1-096 谁管谁叫爹(20分)_pta谁管谁叫爹-CSDN博客

Python代码:

from heapq import heappush,heappop
from bisect import bisect,bisect_left
from math import sqrt,ceil,floor
from collections import deque
import sys
import time
sys.setrecursionlimit(1000010)
sys.set_int_max_str_digits(1000010)
inpu = sys.stdin.readline
prin = sys.stdout.write
#据说python的for循环比while快 又不想让嵌套循环(如果有)的i冲突 可以尝试用无用变量名
n = int(input())
for AAA in range(n):
    na,nb = map(int,input().split())
    sa,sb = 0,0
    tmpa,tmpb = na,nb #tmp作为临时变量
    #计算数位和
    while tmpa > 0:
        sa += tmpa%10
        tmpa //= 10
    while tmpb > 0:
        sb += tmpb%10
        tmpb //= 10
    #判断几种情况
    if na%sb==0 and nb%sa!=0:
        print("A")
    elif nb%sa==0 and na%sb!=0:
        print("B")
    elif na>nb: #都满足或都不满足 判断原先数字大小
        print("A")
    else:
        print("B")

L2-进阶级(100分)

2023年的L2-1和L2-4是简单题,L2-2中等题(容易超时);L2-3难题,需要一定的构造技巧。

L2部分基本上还是涵盖了近年来L2的考点(基本上每年都是这几个考点):

STL容器、复杂模拟、数据结构(树考的偏多)、搜索(或图论),对应题号1-4。

建议多练PTA上的团体程序设计天梯赛的练习集的L2题目,熟练之后会好做很多。

L2的L3一些题目,用其他语言写正解可能会超时,所以最好用C++。

这里给出L2和L3可以用Python的判断时间复杂度方法:

时间复杂度总和少于10^{5}的,除了频繁对列表进行操作(例如for循环、修改值等),放心使用。

除了图论外,给Python延长了时限的题目,放心使用。

C++选手的优秀手速(自己可以尝试训练到这个标准,可以给L3多出很多做题时间):

参加过天梯赛的选手:达到85分:50分钟。达到100分:70分钟。

第一次参加天梯赛的选手,如果L1在1小时内获得了90分以上,在剩余2小时内在L2和L3得到85分及以上就得到了国家三等奖;熟练后可按上述要求练习手速。

L2-1 堆宝塔(25分)

原题链接:​​​​​​​L2-045 堆宝塔 - 团体程序设计天梯赛-练习集

思路:这题不难,按照题目的描述模拟就能出结果了。

提示:1.注意“然后把 B 柱上所有比 C 大的彩虹圈逐一取下放到 A 柱上,最后把 C 也放到 A 柱上。”这一个条件,不是把B柱的所有彩虹圈放到A柱上。

           2.注意对最后一个彩虹圈操作后要判断A塔和B塔有没有彩虹圈,如果有要额外计算。

C++代码:L2-045 堆宝塔 - YuKiCheng - 博客园

Python代码:

from heapq import heappush,heappop
from bisect import bisect,bisect_left
from math import sqrt,ceil,floor
from collections import deque
import sys
import time
sys.setrecursionlimit(1000010)
sys.set_int_max_str_digits(1000010)
inpu = sys.stdin.readline
prin = sys.stdout.write

n = int(input())
d = list(map(int,input().split())) #整行读取数字生成列表
ge,ceng = 0,0 #个数和最高多少层
#A塔和B塔
a = []
b = []
a.append(d[0]) #放置第一个彩虹圈
for i in range(1,len(d)):
    c = d[i]
    if c < a[-1]: #c比a塔顶小 -1的下标意思是列表的最后一个数,-2 -3 ...同理
        a.append(c)
    elif len(b) == 0 or c > b[-1]: #b为空或c比b塔顶大
        b.append(c)
        #print(b) #调试用的语句
    else: #将A摘下来做成品
        ge += 1 
        ce = 0
        while len(a) != 0:
            #print(a) #调试用的语句
            a.pop()
            ce += 1 #获得1个宝塔
        ceng = max(ce,ceng) #取最高层数
        while len(b) != 0 and b[-1] > c: #然后把c大的摘下来套到a
            a.append(b.pop())
        a.append(c)
#最后特判a塔和b塔有彩虹圈的情况
if len(a) != 0:
    ge += 1
    ce = 0
    while len(a) != 0:
        #print(a)
        a.pop()
        ce += 1
    ceng = max(ce,ceng)
if len(b) != 0:
    ge += 1
    ce = 0
    while len(b) != 0:
        #print(b)
        b.pop()
        ce += 1
    ceng = max(ce,ceng)
print(ge,ceng)

L2-2 天梯赛的赛场安排(25分)

原题链接:​​​​​​​L2-046 天梯赛的赛场安排 - 团体程序设计天梯赛-练习集

思路:这道题有一个坑点,属于中等难度,理解题意做的就会清晰了。因为题目说明一个学校剩余的人员一定会集中在一个赛场,所以监考人数就是这所学校占用的赛场数。读者可以拿出笔来算一算。所以:可以边读入边判断,直接输出大学名称和占用赛场数(如果有剩余的人数+1)。剩余的人数在后面简称“余数”。之后如果出现余数,则将这个余数塞入vector中。

之后这道题目的坑点来了:按照尚未安排赛场的队员人数从大到小的顺序!也就说明必须要先将余数排序才能模拟题目给出的步骤。之后按照题目步骤暴力模拟即可(9ms,非常快)。注意Python会超时。

提示:1.注意要先将余数排序才能执行题目的步骤。

           2.有些方法要特判余数的vector是不是空的。

           3.这道题用Python会超时。

C++代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define append push_back //python用习惯 避免写错用define替换了
#define print printf

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n,m;
    int sai = 0; //完整赛场数
    cin>>n>>m;
    vector<int> s; //存储余数
    vector<int> q; //存储余数组成的赛场数量
    for(int i=1;i<=n;i++)
    {
        string a;
        int b;
        cin>>a>>b;
        int tmp = b/m;
        sai += tmp; //凑出tmp个完整的赛场
        int yu = b%m; //剩余的人群(余数)
        if(yu!=0) tmp += 1; //特判余数,加一个监考
        cout<<a<<' '<<tmp<<'\n'; //直接输出
        if(yu != 0)
        {
             s.append(yu); //塞入存储余数的vector
        }
    }
    //sort默认从小到大排序,greater的作用是从大到小排序
    //不会的选手也可以直接排序后reverse这个vector 或者直接暴力swap
    sort(s.begin(),s.end(),greater<int>());
    if(s.size()) //特判没有余数的情况 有余数才能分配赛场
    {
        q.append(s[0]); //最多的余数先安排一个赛场 要特判s是不是空的
        for(int i=1;i<s.size();i++)
        {
             bool fff = 0; //判断是否找到赛场
            for(int j=0;j<q.size();j++)
            {
                 //如果能找到塞进去不超人数的赛场就进去
                 if(s[i]+q[j]<=m)
                {
                    q[j] += s[i];
                    fff = 1;
                    break;
                }
            }
            if (!fff) q.append(s[i]); //找不到赛场就新建一个 使用append原因见上
        }
    }
    cout<<sai+q.size(); //输出完整赛场数和由余数组成的赛场数的总和
}

Python代码:无

L2-3 锦标赛(25分)

原题链接:​​​​​​​L2-047 锦标赛 - 团体程序设计天梯赛-练习集

思路:这道题需要构造,先建立一个55万左右大小的数组(因为再加上最后一层节点的左右孩子,总共个节点),再将这个数组初始化为-1。

之后对每一层选手进行输入,第i层的下标范围是。这样就自然形成一颗完全二叉树了。对最后一层的选手设立左孩子和右孩子(其实就是最后一层的再下一层)。用数组下标存,假设下标为u,则左孩子的下标是2*u,右孩子的下标是2*u+1,并让右孩子的值等于自己。

至于最后一行的节点,可以用下标0存储。

之后再从最后一层自下到上将每一个节点执行pushdown操作。这个操作的步骤是:

           1.获取当前的节点的值(下文称“源节点的值”)和指针(在这里指的是下标)。

           2.对当前节点的左孩子、右孩子搜索枚举。如果左孩子(右孩子)的值小于等于源节点的值,则尝试把节点指针移动到左孩子(或者右孩子),不需要回溯。注意:如果左孩子和右孩子都满足条件,则两种情况都执行一遍。如果指针没到底(就是最后一层的再下一层,即最后一层某个节点的左孩子和右孩子),重复执行这一步。

           3.如果指针到底了,检查值:如果是-1(表示这个位置还没有放置任何数字)而且这个源节点的值能打败右孩子(也就是最底层的那个选手),则将这个数字放入这个位置,之后终止一切搜索的操作;如果不能打败或者不是-1就不用再往下搜索了,因为已经到底。

然后再对0号节点从1号开始执行pushdown操作。操作完毕后,有两种情况输出No Solution:

           1.0号节点的值小于1号节点的值,此时0号不可能是冠军

           2.最后一层的再下一层仍有-1(即未塞满)。

提示:1.直接输出No Solution可以骗分,得到2分。

           2.如果当前节点的值已经放置在最后一层的再下一层,则剪枝。

C++代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define append push_back
#define print printf
int a[600005];
int bas;
bool f = 0;
void insert(int x,int po) //pushdown操作 x为源节点的值 po为当前位置指针(下标)
{
    if(f) return ; //这个节点已经塞入成功了
    if(po>=bas) //从bas开始的下标就是最后一层的再下一层节点了
    {
        //如果这个位置还没塞入 而且 x能打败这位选手
        if(a[po] == -1 && x >= a[po+1])
        {
            a[po] = x; //位置塞入值
            f = 1; //塞入成功
        }
        return ;
    }
    int l = po * 2;
    int r = po * 2 + 1;
    //转移指针到左孩子、右孩子
    if(a[l] <= x) insert(x,l);
    if(a[r] <= x) insert(x,r);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    memset(a,-1,sizeof(a));
    int n;
    cin>>n;
    bas = pow(2,n); //所有输入的下标范围是0到pow(2,n)-1 从bas开始就是最后一层的再下一层
    //对每一层的节点进行输入
    for(int i=n;i>=1;i--) //第i层的所有节点,i从最后一层开始
        for(int j=pow(2,i-1);j<pow(2,i);j++)
            cin>>a[j];
    cin>>a[0]; //输入冠军
    for(int i=bas/2;i<bas;i++) a[i*2+1] = a[i]; //右孩子的值为自己
    //pushdown操作 f表示是否塞入成功
    for(int i=bas/2-1;i>=1;i--) f=0,insert(a[i],i);
    f=0; //塞入0号节点 初始化还没塞入成功
    //swap(a[0],a[1]);
    if(a[0]<a[1]) //0号节点不是冠军
    {
        cout<<"No Solution";
        return 0;
    }
    insert(a[0],1); //塞入0号节点
    for(int i=bas;i<2*bas;i++)
    {
        if(a[i]==-1) //还有位置没被塞入
        {
        cout<<"No Solution";
        return 0; // return 0;表示后面的都不用执行了
        }
    }
    for(int i=bas;i<2*bas;i++) //输出最后一层的再下一层的节点
    {
        if(i!=bas) cout<<' ';
        cout<<a[i];
    }
    return 0;
}

//之前写了个贪心算法造这组数据不能通过 上述算法能通过这组数据
// 3
// 1 1 1 1
// 2 4
// 3
// 4

Python代码:无

L2-4 寻宝图(25分)

原题链接:​​​​​​​L2-048 寻宝图 - 团体程序设计天梯赛-练习集

思路:这道题比L2-2和L2-3简单,用DFS或者BFS做连通块搜索。如果搜到至少1个大于1的数字,就认为这个岛屿上有宝藏。要注意暴力的方法会内存超限,但好在总块数在10万之内。于是可以用一些容器存储。

提示:1.一个岛屿上有多个宝藏时,有宝藏的岛屿只能被算作一个。

           2.用vector或者string存都可以。

           3.注意vis数组或者st数组的存储方式,可以是上述两种容器之一,也可以是其他存储方法。

           4.C++题解的作者使用了DFS,我的题解使用了BFS。

C++代码:【团体程序设计天梯赛】L2-048 寻宝图-CSDN博客

Python代码:

from collections import deque
from math import sqrt,ceil,floor
import sys
sys.setrecursionlimit(1000010)
sys.set_int_max_str_digits(1000010)
inpu = sys.stdin.readline
prin = sys.stdout.write
n,m = map(int,input().split())
a = []
vis = [[0] * (m+1) for i in range(n+1)] #python可以动态开数组
#dx dy数组控制方向
dx = [1,0,-1,0]
dy = [0,1,0,-1]

def bfs(x,y):
    f = 0
    #x y单独构成两个队列 也可以用元组合并成一个
    qx = deque()
    qy = deque()
    qx.append(x)
    qy.append(y)
    while len(qx) != 0:
        cx=qx.popleft()
        cy=qy.popleft()
        if vis[cx][cy] == 1:
            continue
        vis[cx][cy] = 1
        if a[cx][cy] != '0' and a[cx][cy] != '1': #发现宝藏了
            f = 1
        for i in range(4):
            #加入偏移量
            fx,fy = cx+dx[i],cy+dy[i]
            #判断这个点是否是陆地 而且在范围内
            if fx >= 0 and fy >= 0 and fx < n and fy < m and a[fx][fy] != '0':
                qx.append(fx)
                qy.append(fy)
    return f
ans,bao = 0,0 #岛屿数量,有宝藏的岛屿数量
for i in range(n):
    a.append(input()) #直接当字符串塞入a列表
#print(a) #调试语句
for i in range(n):
    for j in range(m):
        #一次搜索连通块时 所有的vis(或者st)都会标记为1 所以搜索次数就是连通块个数
        if vis[i][j] == 0 and a[i][j] != '0':
            ans += 1
            #print(i,j,a[i][j])
            if bfs(i,j) == 1:
                bao += 1
print(ans,bao)

L3-登顶级(90分)

2023年的L3没有一个是简单的题目。L3-1是图论+大模拟;L3-2是树形DP;L3-3基本上不会有多少人写出来。

对于正常的选手来说,L3-1、L3-2、L3-3近几年的得分“风格”有两种:

           1.L3-1接近满分,L3-2用暴力+骗分可以得到20分及以上,L3-3基本不得分;

           2.L3-1接近满分,L3-2和L3-3暴力+骗分总共可以得到20分及以上。

建议多练习骗分技巧,并争取写出80%的L3-1正解;剩下20%能拿多少分就拿多少分。L3-2和L3-3能暴力就暴力;不能暴力就尝试骗分。

关于L3的其他语言超时问题,参见L2介绍。

如果前面大部分的分已经获得,还剩下70分钟及以上做L3的,属于优秀手速的选手。

L3-1可以尝试写出接近正解的答案;L3-2和L3-3建议花5-10分钟想最暴力的思路(无论时间复杂度多高,都能过0号样例,分值最大),如果想不到思路,前面写的也差不多,可以从0到50一个一个(当然有时间可以枚举更多)输出答案骗分。

L3-1 超能力者大赛(30分)

原题链接:​​​​​​​L3-034 超能力者大赛 - 团体程序设计天梯赛-练习集

思路:第一步与扩充说明的描述是:“从所有超能力者(包括联盟)中找出一个与自己能力值最接近、同时自己能够击败的对手,用最短时间去到对方的城市,在到达后第二天击败之,有可能遇到多个符合条件的对手,并列情况下优先选最近的;距离也并列的情况下选途径城市最少的;再有并列就选城市编号最小的。”就可以想到多源最短路。提到多源最短路,就可以想到Floyd算法。维护两个邻接矩阵,第一个邻接矩阵f维护最短距离,第二个邻接矩阵f维护途径的最短城市数。设定好距离后跑floyd最短路。

题目先设定超能力者的初始地点和能力值,记住:0号超能力者是自己,所以先设定自己的能力值后,下标再从1开始输入。推荐用priority_queue的小根堆形式维护敌人的能力值。原因是:假设使用vector维护,某个城市有100个能力值为1的能力者,又有1个能力值为200的能力者,你的能力值为1。击败一个超能力者后,剩下99位能力者合体,插入到200的后面,不符合最小的条件。那么这样,vector在每次击杀完敌人的时候都要sort,可能会超时(我没试过)。

输入完超能力者和边后就可以Floyd了。然后就是大模拟。我将模拟分为3个步骤:寻路,走路,杀敌。我们来拆解这3个步骤:

           1.寻路:根据题目描述找到下一个地点(见思路加粗部分)。设定最终地点的编号初始值是0x3f3f3f3f。先特判所有城市的敌人是否都被击杀了(在这里我用优先队列q[i].size()==0),如果是,返回一个特定值,输出WIN,游戏结束。接下来就是正常的步骤。如果编号到了结束依然是0x3f3f3f3f,则所有人的能力值都比你大,返回特定值,输出Lose,游戏结束。否则执行第2步。注意寻找最接近的能力值需要把每个优先队列都拆开(如果上述使用vector存敌人直接遍历然后erase),即pop到一个临时的队列,之后塞回去;这样才能找到与自己能力最接近的能力者(而不是能力最小的)。见样例1的4号城市,初始堆顶是8,要拆开优先队列才能找到“10”。

           2.走路:每走一步,day++,dist--;如果day到了游戏结束那天,输出Game Over,游戏结束;否则直到dist走完到下一个城市。注意:下一个城市可以是自己本身(见样例2),如果不使自己本身,就输出Move。

           3.杀敌:先拆开这个城市的优先队列(或者vector找到对手并erase),击杀对手。如果天数到了,判输赢和Game Over;增加自己的能力值后,这个城市所有能力小于等于你的超能力者都合并成一个联盟,视为一个超能力者。之后把这个联盟塞入优先队列。一直战斗,直到打不过堆顶,或者所有人已经被你击杀,或者天数到了,判输赢和Game Over

一直重复这3个步骤,直到判断输赢或者游戏结束。

提示:1.这道题非常考验调BUG的能力与做题的心态,我花了接近一个小时获得25分,应该是一些边界的问题。有些情况下会在游戏结束前输出多个WIN、Lose、Game Over,此时设一个bool变量判断游戏终止的语句输出没有,输出过了就不再输出。

           2.下标都是从0开始的,道路是双向的。

           3.如果下一个目的地是当前城市,不能输出Move语句。

           4.先合并能力值,再执行“敌人合体成联盟”的操作。

           5.到了最后一天,先判断输赢,再判断Game Over。

           6.即使这道题的Python时限开到900ms,Python代码在Floyd结束后就超时了。

           7.目前在网络上没有找到公开的正解。

C++代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define append push_back
#define print printf

int n,m,me,d;
int f[205][205]; //存最短路
int f2[205][205]; //存最短途径点数
int mypos,mynengli; //你当前所处的城市编号和能力值
int day,jiejin; //day是天数 jiejin是最接近你能力的超能力者的能力值
priority_queue<int,vector<int>,greater<int> > q[205]; //每个城市的超能力者存在优先队列
bool shuchu = 0;
void floyd()
{
    for(int k=0;k<=202;k++)
        for(int i=0;i<=202;i++)
            for(int j=0;j<=202;j++)
            {
                if(f[i][j] > f[i][k]+f[k][j]) //距离为第一关键字更新
                {
                    f[i][j] = f[i][k] + f[k][j];
                    f2[i][j] = f2[i][k] + f2[k][j];
                } //距离一样,经过条数为第二关键字更新
                else if(f[i][j] == f[i][k]+f[k][j] && f2[i][j] > f2[i][k]+f2[k][j])
                {
                    f2[i][j] = f2[i][k] + f2[k][j];
                }
            }
}

int select() //选点
{
    int mincha = 0x3f3f3f3f; //最小能力差
    int dist = 0x3f3f3f3f; //距离
    int tujing = 0x3f3f3f3f; //途径点数
    int bian = 0x3f3f3f3f; //下一个要到的城市编号
    bool gg = 1; //所有敌人都被击杀的标记
    for(int i=0;i<m;i++) if(q[i].size()!=0) gg = 0; //有城市的敌人还没被击杀
    if(gg) return -1; //所有敌人被击杀 返回胜利
    for(int i=0;i<m;i++) //顺序枚举保证取到编号最小
    {
        if(q[i].size() == 0) continue; //没人了
        if(mynengli < q[i].top()) continue; //比你强
        //拆优先队列找最接近的操作
        queue<int> tmp;
        int cha = mynengli - q[i].top();
        //能力小于等于你的人 一个个找
        while(q[i].size() && mynengli >= q[i].top())
        {
            tmp.push(q[i].top());
            cha = min(cha,mynengli - q[i].top()); //一个个更新
            q[i].pop();
            if(cha == 0) break; //刚好遇到与你一样的既不用继续找了
        }
        //保证将优先队列复原成原样 因为pop了最小 push的也会是最小
        while(tmp.size()) q[i].push(tmp.front()),tmp.pop();
        if(cha < mincha) //能力差值为第一关键字
        {
            jiejin = mynengli - cha;
            mincha = cha;
            dist = f[mypos][i];
            tujing = f2[mypos][i];
            bian = i;
        }
        else if(cha == mincha && f[mypos][i] < dist) //距离为第二关键字
        {
            dist = f[mypos][i];
            tujing = f2[mypos][i];
            bian = i;
        }//途径个数为第三关键字 此时要严格小于号 保证取到的编号最小
        else if(cha == mincha && f[mypos][i] == dist && f2[mypos][i] < tujing)
        {
            tujing = f2[mypos][i];
            bian = i;
        }
    }
    //cout<<mincha<<' '<<dist<<' '<<tujing<<' '<<bian<<'\n'; //调试语句
    return bian; //如果bian还是0x3f3f3f3f 就说明没有能力<=你 你输了
}

void zhandou(int u) //战斗
{
        //先击杀那位超能力者
        queue<int> tmp;
        //拆队列操作
        while(q[u].size() && q[u].top() != jiejin)
        {
            tmp.push(q[u].top());
            q[u].pop();
        }
        int p = q[u].top();
        mynengli += p; //先加能力值
        print("Get %d at %d on day %d.\n",q[u].top(),mypos,day);
        //将那位接近能力者取出来,表示不在队列中已经被击杀
        q[u].pop();
        //复原优先队列操作
        while(tmp.size()) q[u].push(tmp.front()),tmp.pop();
        day += 1; //击杀一个敌人day++
        //特判时间到,下同
        if(day > d && !shuchu) //shuchu表示已经输出语句了 这点在提示有说
        {
            shuchu = 1; //表示已经输出结束条件
            int nextpos = select(); //选城市 返回WIN Lose 或正常编号(就是Game Over)
            if(nextpos == -1) //所有城市优先队列为空 没有敌人了
            {
                print("WIN on day %d with %d!\n",min(d,day),mynengli);
            }
            else if(nextpos == 0x3f3f3f3f) //都比你大
            {
                print("Lose on day %d with %d.\n",min(d,day),mynengli);
            }//还能到下一个城市 说明还有<=你的敌人
            else print("Game over with %d.\n",mynengli);
            return ;
        }
        //求<=你能力值的人的总和
        int su = 0;
        while(q[u].size() && mynengli >= q[u].top()) su+=q[u].top(),q[u].pop();
        if(su != 0) q[u].push(su); //特判没有这种敌人,防止凭空出现一个能力值为0的敌人
    //继续击杀操作,流程和上面基本是一样的,就不做注释了
    while (q[u].size() && mynengli >= q[u].top())
    {
        p = q[u].top();
        mynengli += p;
        print("Get %d at %d on day %d.\n",q[u].top(),mypos,day);
        q[u].pop();
        day += 1;
        if(day > d && !shuchu)
        {
            shuchu = 1;
            int nextpos = select();
            if(nextpos == -1)
            {
                print("WIN on day %d with %d!\n",min(d,day),mynengli);
            }
            else if(nextpos == 0x3f3f3f3f)
            {
                print("Lose on day %d with %d.\n",min(d,day),mynengli);
            }
            else print("Game over with %d.\n",mynengli);
            return ;
        }
        su = 0;
        while(q[u].size() && mynengli >= q[u].top()) su+=q[u].top(),q[u].pop();
        if(su != 0) q[u].push(su);
    }
    return ;
}
int main()
{
    memset(f,0x3f,sizeof(f));//初始化距离无穷大
    //用了printf,不能用关同步流加速cin和cout操作
    // ios::sync_with_stdio(false);
    // cin.tie(0);
    // cout.tie(0);
    cin>>n>>m>>me>>d;
    for(int i=0;i<=202;i++) f[i][i] = 0;//同一个城市的距离是0
    //先输入自己的初始城市和初始能力值
    cin>>mypos>>mynengli;
    for(int i=2;i<=n;i++) //少了自己的所有能力者总数
    {
        //敌人所在城市与能力值
        int cpos,cnengli;
        cin>>cpos>>cnengli;
        q[cpos].push(cnengli); //插入优先队列维护最小值
    }
    for(int i=1;i<=me;i++)
    {
        int l,r,di;
        cin>>l>>r>>di; //输入两个城市与距离 题目说保证每条边只出现1次
        f[l][r] = di;//双向距离
        f[r][l] = di;//同上
        f2[l][r] = 1;//途径点个数
        f2[r][l] = 1;//同上
    }
    floyd(); //多源最短路
    day = 1; //第1天开始
    while(day <= d)
    {
        int nextpos = select(); 
        //判断输赢逻辑参见战斗函数
        if(nextpos == -1)
        {
            print("WIN on day %d with %d!\n",min(d,day),mynengli);
            break;
        }
        if(nextpos == 0x3f3f3f3f)
        {
            print("Lose on day %d with %d.\n",min(d,day),mynengli);
            break;
        }
        if(day == d+1)
        {
            print("Game over with %d.\n",mynengli);
            break;
        }
        int dist = f[mypos][nextpos];
        bool jieshu = 0;
        while(dist > 0)
        {
            day += 1;
        if(day > d)
        {
            jieshu = 1; //天数超过,表示结束
            nextpos = select(); //先判断输赢
            if(nextpos == -1)
            {
                print("WIN on day %d with %d!\n",day,mynengli);
            }
            else if(nextpos == 0x3f3f3f3f)
            {
                print("Lose on day %d with %d.\n",day,mynengli);
            }
            else print("Game over with %d.\n",mynengli);
            break;
        }
            dist -= 1;
        }
        if(jieshu) break; //天数到了,游戏结束,不能去下一个城市
        //没有去其他城市时不能输出这句话
        if(mypos != nextpos) print("Move from %d to %d.\n",mypos,nextpos);
        mypos = nextpos; //移动到下一个城市(可以是自己)
        zhandou(mypos); //在下一个城市战斗
        //break;
    }
}

Python代码:无

L3-2 完美树(30分)

原题链接:​​​​​​​L3-035 完美树 - 团体程序设计天梯赛-练习集

思路:骗分法,通过assert测试点可以发现前3个测试点的n<=15(后3个测试点n=100000),总价值17分。于是可以用二进制枚举所有点,该点所在的二进制位是0为白,1为黑。对所有种情况进行枚举,如果该树是完美树,判断所有点的初始颜色和二进制位的颜色是否一致,不一致就加上染色代价。之后在种情况中的合法情况中取最小的代价即可。时间复杂度

提示:1.据说当年这道题有人输出20得到15分。我尝试了一下:前3个测试点,一个答案是20;一个答案是0;还有一个答案是权值最小的那个节点,共17分。

           2.C++的assert在天梯赛很有用,它的用法是:assert(条件);条件的写法和if里面的条件一模一样,例如assert(n<=15);如果assert里面的条件为假,PTA对应的测试点会立即返回“运行时错误”。这样你就可以确定这道题目的测试点范围、特征方便骗分;或者用在你认为非常坑的题目去测试有没有你猜想的坑点。Python的assert也一样,用法是:一行 assert n <= 15 不需要加任何符号。

           3.正解:2023 GPLT 天梯赛 L3-035 完美树 —— 树形DP,状态机,贪心-CSDN博客

C++代码:

//二进制枚举骗分法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//color表示原先的颜色 dj是代价 col是二进制枚举的染色
ll color[100005],dj[100005],col[100005];
//储存节点的儿子
vector<int> to[100005];
ll mindj = (ll)(1e18); //最小代价
int n;
bool f = 1; //表示是完美树
pair<int,int> dfs(int u) //统计子树黑白节点树
{
    if(!f) return {0,0}; //不符合 不用再搜索了
    int bai=0;
    int hei=0;
    if(col[u]) hei ++;
    else bai ++;
    for(auto i:to[u]) 
    {
        pair<int,int> res = dfs(i);
        bai += res.first;
        hei += res.second;
    }
    if(abs(bai-hei)>1) f=0; //不符合完美树条件
    return {bai,hei}; //要同时返回2个值 就用pair
}
void pd(int u)
{
    f = 1; //假定这个树是完美树
    for(int i=1;i<=n;i++)
        col[i] = (u>>(i-1)) & 1; //i是从1开始的,二进制是从0次方开始的 所以要i-1
    dfs(1);
    if(f) //如果是完美树 更新最小的代价
    {
        ll su = 0;
        for(int i=1;i<=n;i++)
            if(col[i] != color[i]) su += dj[i];
        mindj = min(mindj,su);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    //每一行前3个是颜色 代价 孩子个数
    for(int i=1;i<=n;i++)
    {
        ll c,p,kk;
        cin>>c>>p>>kk;
        color[i] = c;
        dj[i] = p;
        for(int j=1;j<=kk;j++) //输入所有孩子
        {
            int x;
            cin>>x;
            to[i].push_back(x);
        }
    }
    //二进制枚举 n=100000会爆int 不过即使将n=100000换成n=10 也骗不了分
    for(int i=0;i<(1<<n);i++)
        pd(i);
    cout<<mindj;
}

Python代码:

#输出答案骗分法
#print(20) 0
#print(0) 1
#print(s[0]) 2
import random
n=int(input())
s =[]
for i in range(n):
    t=list(map(int,input().split()))
    s.append(t[1]) #第二个输入的是代价 故下标为1
s.sort()
p = list(set(s))

if n == 2:
    print(s[0]) #最小的那个节点代价
elif n == 1:
    print(0)
elif n < 100:
    print(20)
else:
    print(sum(p)) #输出一个你认为可能的数字 甚至是rand 说不定就骗到分了

L3-3 血染钟楼(30分)

原题链接:​​​​​​​L3-036 血染钟楼 - 团体程序设计天梯赛-练习集

思路:骗分法,也是二进制枚举骗分,用Python得到10分(C++可以得到11分)。时间复杂度是方法参考我的另外一篇文章(已经贴在了下方)。

提示:1.PTA网站上的团体程序设计天梯赛-练习集的L3-036 血染钟楼有陈越姥姥准备的彩蛋,可以看题目解析,但没有贴出正解代码。

           2.地址:2023天梯赛L3-3 血染钟楼10/30分题解(附带骗分技巧)_天梯赛l3题解-CSDN博客

           3.目前在网络上没有找到公开的正解。

C++代码:

#include <iostream>
#include <vector>
#include <cmath>

using namespace std;

int n, m;
vector<pair<int, int>> s;

bool pp(int x, int y, int u) {
    for (int i = 0; i < m; ++i) {
        if ((u >> i) & 1) {
            // 该区间是1区间,所有点都不在区间内,返回假
            if ((x >= s[i].first && x <= s[i].second) || (y >= s[i].first && y <= s[i].second)) {
                continue;
            } else {
                return false;
            }
        } else {
            // 该区间是0区间,有点在区间内,返回假
            if ((x >= s[i].first && x <= s[i].second) || (y >= s[i].first && y <= s[i].second)) {
                return false;
            }
        }
    }
    // 符合了所有要求
    return true;
}

bool pd(int u) {
    // 可行方法数
    int re = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = i + 1; j <= n; ++j) {
            if (pp(i, j, u)) {
                re++;
                // 放置方案不唯一,返回假
                if (re == 2) {
                    return false;
                }
            }
        }
    }
    if (re == 1) {
        return true;
    }
    return false;
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        cin >> n >> m;
        s.clear();
        int ans = 0;
        // 记录区间
        for (int i = 0; i < m; ++i) {
            int l, r;
            cin >> l >> r;
            s.push_back({l, r});
        }
        for (int i = 0; i < (1 << m); ++i) {
            if (pd(i)) {
                ans++;
            }
        }
        cout << ans << endl;
    }
    return 0;
}

Python代码:

import sys
inpu = sys.stdin.readline
prin = sys.stdout.write
#时间复杂度达到了恐怖的O(n^2 * 2^m)
#枚举x和y点来判断是否符合所有要求
def pp(x,y,u):
    for i in range(m):
        #二进制划分区间是0区间还是1区间
        if (u>>i) & 1 == 1:
            #该区间是1区间,所有点都不在区间内,返回假
            if (x >= s[i][0] and x <= s[i][1]) or (y >= s[i][0] and y <= s[i][1]):
                pass
            else:
                return 0
        else:
            #该区间是0区间,有点在区间内,返回假
            if (x >= s[i][0] and x <= s[i][1]) or (y >= s[i][0] and y <= s[i][1]):
                return 0
    #符合了所有要求
    return 1
def pd(u):
    #可行方法数
    re = 0
    for i in range(1,n+1):
        for j in range(i+1,n+1):
            if pp(i,j,u) == 1:
                re += 1
                #放置方案不唯一,返回假
                if re == 2:
                    return 0
    if re == 1:
        return 1
    return 0
 
#快读快写(参考代码开头)
T = int(inpu())
for AAA in range(T):
    n,m = map(int,inpu().split())
    #有意在测试用例中构造异常/错误,使得我们能够探测题目范围
    #类似的还有根据测试点范围骗分的方法
    #避免后面几个测试点耗时 我只要第一个测试点
    #注释掉也只能过第一个(看)
    #if m > 10:
    #    print(1//0)
    s=[]
    ans = 0
    #记录区间
    for i in range(m):
        l,r = map(int,inpu().split())
        #print(l,r)
        s.append((l,r))
    for i in range(0,(1<<m)):
        if pd(i) == 1:
           ans += 1
    print(ans)

感谢您的观看!阅读这么久了,来一个赞~(旺柴)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值