各种各样的搜索(⊙ ▽ ⊙)巩固提升之章

本文通过一系列编程竞赛题目,展示了搜索算法在解决信息技术问题中的应用,包括深搜、广搜、IDDFS、记忆化搜索和A*算法等。题目涵盖生日蛋糕最小表面积、单词游戏、着色方案、八数码难题、骑士精神和世界冰球锦标赛等问题,展示了搜索算法在求解复杂问题时的有效性和灵活性。
摘要由CSDN通过智能技术生成

各种各样的搜索(⊙ ▽ ⊙)巩固提升之章

蓝桥杯之前的一些小训练,主要是蓝题和紫题

一、[NOI1999] 生日蛋糕

题目描述

7 月 17 日是 Mr.W 的生日,ACM-THU 为此要制作一个体积为 M 层生日蛋糕,每层都是一个圆柱体。

设从下往上数第 i(1≤iM)层蛋糕是半径为 Ri,高度为 Hi 的圆柱。当 i<M 时,要求 Ri>Ri+1 且 Hi>Hi+1。

由于要在蛋糕上抹奶油,为尽可能节约经费,我们希望蛋糕外表面(最下一层的下底面除外)的面积 Q 最小。

请编程对给出的 NM,找出蛋糕的制作方案(适当的 RiHi 的值),使 S=πQ 最小。

(除 Q 外,以上所有数据皆为正整数)

输入格式

第一行为一个整数 NN≤2×10^4),表示待制作的蛋糕的体积为

第二行为 MM≤15),表示蛋糕的层数为 M

输出格式

输出一个整数 S,若无解,输出 0。

输入输出样例

输入 #1
100
2
输出 #1
68

剪枝题,这种题感觉确实比较吃经验,基本思路就是深搜,试试各种深度,高度的情况,剪枝都在代码里注释了

AC code

#include <bits/stdc++.h>
//#pragma GCC optimize(3,"Ofast","inline")
#define re register
#define ll long long
#define ull unsigned long long
using namespace std;
//速读
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}

int n, m;
int r[30], h[30];
int minn = 2147483647;
void dfs(int x, int y, int k, int z){
    //如果体积炸了,就剪枝
    if(y < 0){
        return;
    }
    //如果层数炸了,就剪枝
    if(x > m + 1){
        return;
    }
    //如果现在的面积已经大于最小总面积,就剪枝
    if(k >= minn){
        return;
    }
    //如果符合条件,就出去,这是正常深搜的步骤
    if(y == 0 && x == m + 1){
        //最后再加整个的面积,这样搜的时候就只加侧面面积就行
        k += r[1] * r[1];
        if(k < minn){
            minn = k;
            return;
        }
    }
    //如果当前面积加上后面理论最小面积已经超了,就剪枝
    if(k + z + r[1] * r[1] > minn){
        return;
    }
    //和上面那个差不多,如果体积拉满还是不够,那就剪了
    if(y - r[x - 1] * r[x - 1] * h[x - 1] * z > 0){
        return;
    }
    //正常的搜索------为啥到z,因为后面每层至少有1个高度
    for(int i = r[x - 1] - 1; i >= z; i--){
        for(int j = h[x - 1] - 1; j >= z; j--){
            //各种半径高度都试试
            if(y - i * i * j >= 0 && x + 1 <= m + 1){
                r[x] = i;
                h[x] = j;
                dfs(x + 1, y - i * i * j, k + (i * 2 * j), z - 1);
                r[x] = 0;
                h[x] = 0;
            }
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m;
    //这个地方想了好久,可能要结合后面代码来理解,这个地方其实是给了个最大值,用于辅助剪枝
    r[0] = (int)sqrt(n);
    h[0] = (int)sqrt(n);
    dfs(1, n, 0, m);
    if(minn == 2147483647){
        cout<< 0 <<endl;
    }else{
        cout<< minn <<endl;
    }
    return 0;
}

二、单词游戏

题目描述

Io和Ao在玩一个单词游戏。

他们轮流说出一个仅包含元音字母的单词,并且后一个单词的第一个字母必须与前一个单词的最后一个字母一致。

游戏可以从任何一个单词开始。

任何单词禁止说两遍,游戏中只能使用给定词典中含有的单词。

游戏的复杂度定义为游戏中所使用的单词长度总和。

编写程序,求出使用一本给定的词典来玩这个游戏所能达到的游戏最大可能复杂度。

输入格式

输入文件的第一行,表示一个自然数N(1≤N≤16),N表示一本字典中包含的单词数量以下的每一行包含字典中的一个单词,每一个单词是由字母A、E、I、O和U组成的一个字符串,每个单词的长度将小于等于100,所有的单词是不一样的。

输出格式

输出文件仅有一行,表示该游戏的最大可能复杂度。

输入输出样例

输入 #1
5
IOO
IUUO
AI
OIOOI
AOOI
输出 #1
16

这道题题解里提到了记忆化搜索都可以用dp,这道题确实是状压dp过的,以后一定分析一下看看是不是这样。其实说到是状压估计思路就很清楚了,16位的数字代表状态,然后dp就行了

AC code

#include <bits/stdc++.h>
#pragma GCC optimize(3,"Ofast","inline")
#define re register
#define ll long long
#define ull unsigned long long
#define r read()
using namespace std;
//速读
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
int f[(1 << 16)][17], n, ans;
string s[105];
int main()
{
    ios::sync_with_stdio(false);
    cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> s[i];
        f[1 << (i - 1)][i] = s[i].size();
    }
    //枚举状态
    for(int k = 0; k < (1 << n); k++){
        //枚举当前的单词
        for(int i = 1; i <= n; i++){
            //枚举要接的单词
            for(int j = 1; j <= n; j++){
                if(i != j && s[i][s[i].size() - 1] == s[j][0] && (k & (1 << (i - 1))) && !(k & (1 << (j - 1)))){
                    f[k + (1 << (j - 1))][j] = max(f[k + (1 << (j - 1))][j], f[k][i] + (int)s[j].size());
                }
            }
        }
    }
    int ans = 0;
    for(int i = 0; i < (1 << n); i++){
        for(int j = 1; j <= n; j++){
            ans = max(ans, f[i][j]);
        }
    }
    cout<<ans<<endl;
    return 0;
}

三、[SCOI2008]着色方案

题目描述

n 个木块排成一行,从左到右依次编号为 1 至 n

你有 k 种颜色的油漆,第 i 种颜色的油漆足够涂 ci 个木块。

所有油漆刚好足够涂满所有木块,即n∑i=1kci=n

由于相邻两个木块涂相同色显得很难看,所以你希望统计任意两个相邻木块颜色不同的着色方案。

由于答案可能很大,请输出对 10^9+7 取模的结果。

输入格式

第一行,一个整数 k,表示颜色数量。

第二行 k 个整数 c1,c2,…,ck,表示每种颜色能够涂木块的个数。

输出格式

一行一个整数,表示答案对 10^9+7 取模的结果。

输入输出样例

输入 #1
3
1 2 3
输出 #1
10
输入 #2
5
2 2 2 2 2
输出 #2
39480
输入 #3
10
1 1 2 2 3 3 4 4 5 5
输出 #3
85937576

说明/提示

  • 对于 50% 的数据,1≤k≤5,1≤ci≤3;
  • 对于 100% 的数据,1≤k≤15,1≤ci≤5。

开一个六维的dp数组,含义是有a种能用1次的,b种能用两次的等等油漆,并且上一次用的是能用last次的油漆的情况下,我下一次有多少种选择。然后深搜➕dp,看看每次用不同的油漆的情况。

AC code

#include <bits/stdc++.h>
//#pragma GCC optimize(3,"Ofast","inline")
#define re register
#define ll long long
#define ull unsigned long long
#define r read()
using namespace std;
//速读
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
//前五个分别代表能刷的次数,最后一个代表上次用的油漆
ll dp[16][16][16][16][16][6];
//记录各油漆个数
int t[6];
int n;
ll dfs(int a, int b, int c, int d, int e, int last){
    if(dp[a][b][c][d][e][last] != -1){
        return dp[a][b][c][d][e][last];
    }
    if(a + b + c + d + e == 0){
        return 1;
    }
    ll ans = 0;
    if(a){
        ans += (a - (last == 2)) * dfs(a - 1, b, c, d, e, 1);
    }
    if(b){
        ans += (b - (last == 3)) * dfs(a + 1, b - 1, c, d, e, 2);
    }
    if(c){
        ans += (c - (last == 4)) * dfs(a, b + 1, c - 1, d, e, 3);
    }
    if(d){
        ans += (d - (last == 5)) * dfs(a, b, c + 1, d - 1, e, 4);
    }
    if(e){
        ans += e * dfs(a, b, c, d + 1, e - 1, 5);
    }
    dp[a][b][c][d][e][last] = ans % 1000000007;
    return dp[a][b][c][d][e][last];
}
int main()
{
    ios::sync_with_stdio(false);
    n = r;
    for(int i = 1; i <= n; i++){
       int x = r;
       t[x]++;
    }
    memset(dp, -1, sizeof(dp));
    cout<<dfs(t[1], t[2], t[3], t[4], t[5], 0);
    return 0;
}

四、八数码难题

题目描述

在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

输入格式

输入初始状态,一行九个数字,空格用0表示

输出格式

只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

输入输出样例

输入 #1
283104765
输出 #1
4

IDA**,基于迭代加深的A*算法,感觉就是剪枝,判断如果全理想化次数都不够那就不继续搜了。然后这题还用了一个最优性优化,就是如果两步是重复的就直接排除,简单说就是不连续走回头路

AC code

#include <bits/stdc++.h>
//#pragma GCC optimize(3,"Ofast","inline")
#define re register
#define ll long long
#define ull unsigned long long
#define r read()
using namespace std;
//速读
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}

string s;
int ans[4][4] = {
    {0,0,0,0},
    {0,1,2,3},
    {0,8,0,4},
    {0,7,6,5},
};
int a[5][5], k = 1, judge = 0;
int nxtx[] = {0, 1, -1, 0};
int nxty[] = {1, 0, 0, -1};
//判定
int check(){
    for(int i = 1; i <= 3; i++){
        for(int j = 1; j <= 3; j++){
            if(ans[i][j] != a[i][j]){
                return 0;
            }
        }
    }
    return 1;
}
//估价
int test(int step){
    int cnt = 0;
    for(int i = 1; i <= 3; i++){
        for(int j = 1; j <= 3; j++){
            if(ans[i][j] != a[i][j]){
                cnt++;
                if(cnt + step > k){
                    return 0;
                }
            }
        }
    }
    return 1;
}
void A_star(int step, int x, int y, int pre){
    if(step == k){
        if(check()){
            judge = 1;
        }
        return;
    }
    if(judge){
        return;
    }
    for(int i = 0; i < 4; i++){
        int nx = x + nxtx[i], ny = y + nxty[i];
        if(nx < 1 || nx > 3 || ny < 1 || ny > 3 || pre + i == 3){
            continue;
        }
        swap(a[x][y], a[nx][ny]);
        if(test(step) && !judge){
            A_star(step+1, nx, ny, i);
        }
        swap(a[x][y], a[nx][ny]);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    int x, y;
    cin >> s;
    for(int i = 0; i < 9; i++){
        a[i / 3 + 1][i % 3 + 1] = s[i] - '0';
        if(a[i / 3 + 1][i % 3 + 1] == 0){
            x = i / 3 + 1;
            y = i % 3 + 1;
        }
    }
    if(check()){
        cout<<0<<endl;
        return 0;
    }
    for(;k;k++){
        A_star(0, x, y, -1);
        if(judge){
            cout<<k<<endl;
            break;
        }
    }
    return 0;
}

五、[SCOI2005]骑士精神

题目描述

img

输入格式

第一行有一个正整数T(T<=10),表示一共有N组数据。接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑士,*表示空位。两组数据之间没有空行。

输出格式

对于每组数据都输出一行。如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出-1。

输入输出样例

输入 #1
2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100
输出 #1
7
-1

说明/提示

img

做到这题发现IDA*的模板性真的好强,这题一看就和上一题完全一样

AC code

#include <bits/stdc++.h>
#pragma GCC optimize(3,"Ofast","inline")
#define re register
#define ll long long
#define ull unsigned long long
#define r read()
using namespace std;
//速读
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}

string s;
int ans[7][7] = {
    {0,0,0,0,0,0},
    {0,1,1,1,1,1},
    {0,0,1,1,1,1},
    {0,0,0,2,1,1},
    {0,0,0,0,0,1},
    {0,0,0,0,0,0}
};
int a[10][10], k = 1, judge = 0;
int nxtx[] = {1, 1, 2, 2, -2, -2, -1, -1};
int nxty[] = {2, -2, 1, -1, 1, -1, 2, -2};
//判定
int check(){
    for(int i = 1; i <= 5; i++){
        for(int j = 1; j <= 5; j++){
            if(ans[i][j] != a[i][j]){
                return 0;
            }
        }
    }
    return 1;
}
//估价
int test(int step){
    int cnt = 0;
    for(int i = 1; i <= 5; i++){
        for(int j = 1; j <= 5; j++){
            if(ans[i][j] != a[i][j]){
                cnt++;
                if(cnt + step > k){
                    return 0;
                }
            }
        }
    }
    return 1;
}
void A_star(int step, int x, int y, int pre){
    if(step == k){
        if(check()){
            judge = 1;
        }
        return;
    }
    if(judge){
        return;
    }
    for(int i = 0; i <= 7; i++){
        int nx = x + nxtx[i], ny = y + nxty[i];
        if(nx < 1 || nx > 5 || ny < 1 || ny > 5 || pre + i == 7){
            continue;
        }
        swap(a[x][y], a[nx][ny]);
        if(test(step) && !judge){
            A_star(step+1, nx, ny, i);
        }
        swap(a[x][y], a[nx][ny]);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    int x, y;
    int t;
    cin >> t;
    for(int p = 1; p <= t; p++){
        judge = 0;
        for(int i = 1; i <= 5; i++){
            cin >> s;
            for(int j = 0; j < 5; j++){
                if(s[j] == '*'){
                    a[i][j+1] = 2;
                    x = i, y = j + 1;
                }else{
                    a[i][j+1] = s[j] - '0';
                }
            }
        }
        if(check()){
            cout<<0<<endl;
            return 0;
        }
        for(k = 1; k <= 15; k++){
            A_star(0, x, y, -1);
            if(judge){
                cout<<k<<endl;
                break;
            }
        }
        if(!judge){
            cout<<-1<<endl;
        }
    }
    return 0;
}

六、[CEOI2015 Day2]世界冰球锦标赛

题目描述

译自 CEOI2015 Day2 T1「Ice Hockey World Championship

今年的世界冰球锦标赛在捷克举行。Bobek 已经抵达布拉格,他不是任何团队的粉丝,也没有时间观念。他只是单纯的想去看几场比赛。如果他有足够的钱,他会去看所有的比赛。不幸的是,他的财产十分有限,他决定把所有财产都用来买门票。

给出 Bobek 的预算和每场比赛的票价,试求:如果总票价不超过预算,他有多少种观赛方案。如果存在以其中一种方案观看某场比赛而另一种方案不观看,则认为这两种方案不同。

输入格式

第一行,两个正整数 NM(1≤N≤40,1≤M≤10^18),表示比赛的个数和 Bobek 那家徒四壁的财产。

第二行,N 个以空格分隔的正整数,均不超过 10^16,代表每场比赛门票的价格。

输出格式

输出一行,表示方案的个数。由于 N 十分大,注意:答案 ≤2^40。

输入输出样例

输入 #1
5 1000
100 1500 500 500 1000
输出 #1
8

说明/提示

样例解释

八种方案分别是:

  • 一场都不看,溜了溜了
  • 价格 100 的比赛
  • 第一场价格 500 的比赛
  • 第二场价格 500 的比赛
  • 价格 100 的比赛和第一场价格 500 的比赛
  • 价格 100 的比赛和第二场价格 500 的比赛
  • 两场价格500 的比赛
  • 价格 1000 的比赛

有十组数据,每通过一组数据你可以获得 10 分。各组数据的数据范围如下表所示:

数据组号1−23−45−78−10
N10204040
M10^610^1810^610^18

这是之前做的题了,拿来复习一下二分搜索,正好当时忘写题解了,就补在这里。其实思想就是,分成两段来搜索,然后合起来,关键是怎么合,其实很简单,就是a的情况和b的情况加起来,满足条件就ans++,所以就是排序二分即可

AC code

#include <bits/stdc++.h>
//#pragma GCC optimize(3,"Ofast","inline")
//#define re register
//#define ll long long
#define ull unsigned long long
#define r read()
using namespace std;
//速读
inline int read();
int n,mid;
ull a[50];
ull mon;
ull ans;
vector <ull> va, vb;
void dfs(int le, int ri, ull cnt, vector<ull> &vk){
    if(cnt > mon){
        return;
    }
    if(le > ri){
        vk.push_back(cnt);
        return;
    }
    dfs(le + 1, ri,cnt + a[le], vk);
    dfs(le + 1, ri,cnt, vk);
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> mon;
    for(int i = 1 ; i <= n ; i++){
        cin >> a[i];
    }
    mid = n >> 1;
    dfs(1, mid, 0,va);
    dfs(mid+1, n, 0, vb);
    sort(va.begin(), va.end());
    for(int i = 0; i < vb.size(); i++){
//        cout<<"check"<<endl;
        ans += upper_bound(va.begin(), va.end(), mon - vb[i]) - va.begin();
    }
    cout<<ans<<endl;
    return 0;
}
//速读
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}

七、CF525E Anya and Cubes

题目描述

Anya loves to fold and stick. Today she decided to do just that.

Anya has nn cubes lying in a line and numbered from 11 to nn from left to right, with natural numbers written on them. She also has kk stickers with exclamation marks. We know that the number of stickers does not exceed the number of cubes.

Anya can stick an exclamation mark on the cube and get the factorial of the number written on the cube. For example, if a cube reads 55 , then after the sticking it reads 5!5! , which equals 120120 .

You need to help Anya count how many ways there are to choose some of the cubes and stick on some of the chosen cubes at most kk exclamation marks so that the sum of the numbers written on the chosen cubes after the sticking becomes equal to SS . Anya can stick at most one exclamation mark on each cube. Can you do it?

Two ways are considered the same if they have the same set of chosen cubes and the same set of cubes with exclamation marks.

输入格式

The first line of the input contains three space-separated integers nn , kk and SS ( 1<=n<=251<=n<=25 , 0<=k<=n0<=k<=n , 1<=S<=10^{16}1<=S<=1016 ) — the number of cubes and the number of stickers that Anya has, and the sum that she needs to get.

The second line contains nn positive integers a_{i}a**i ( 1<=a_{i}<=10^{9}1<=a**i<=109 ) — the numbers, written on the cubes. The cubes in the input are described in the order from left to right, starting from the first one.

Multiple cubes can contain the same numbers.

输出格式

Output the number of ways to choose some number of cubes and stick exclamation marks on some of them so that the sum of the numbers became equal to the given number SS .

题意翻译

给你nn 个数,n\le 26n≤26 初始序列为a_i,0\le a_i\le 10^9a**i,0≤a**i≤109

你有kk 个!! ,每个!! 可以使序列中的一个数变成a_i!a**i!

例如5!=1205!=120

求:选出任意个数使他们和的等于S的方案数

输入格式

第一行n,k,Sn,k,S

第二行n个数,分别代表a_ia**i

输出

一行一个整数,选出数的合法方案数

感谢@s_a_b_e_r 提供的翻译

输入输出样例

输入 #1
2 2 30
4 3
输出 #1
1
输入 #2
2 2 7
4 3
输出 #2
1
输入 #3
3 1 1
1 1 1
输出 #3
6

说明/提示

In the first sample the only way is to choose both cubes and stick an exclamation mark on each of them.

In the second sample the only way is to choose both cubes but don’t stick an exclamation mark on any of them.

In the third sample it is possible to choose any of the cubes in three ways, and also we may choose to stick or not to stick the exclamation mark on it. So, the total number of ways is six.

和上一道题一样的思路,厉害的是STL的优化,真就为所欲为

#include <bits/stdc++.h>
//#pragma GCC optimize(3,"Ofast","inline")
#define re register
#define ll long long
#define ull unsigned long long
#define r read()
using namespace std;
//速读
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}

const int N = 30;
unordered_map<long long, long long>M[N];
ll fact[N];
int n, k, a[N];
ll s, ans;

void dfs1(int no, int en, ll S, int used){
    if(used > k){
        return;
    }
    if(S > s){
        return;
    }
    if(no > en){
        M[used][S]++;
        return;
    }
    //三搜
    //1 不拿
    //2 拿
    //3 拿阶乘 超过20就崩了
    dfs1(no + 1, en, S, used);
    dfs1(no + 1, en, S + a[no], used);
    if (a[no] <= 20){
        dfs1(no + 1, en, S + fact[a[no]], used + 1);
    }
}

void dfs2(int no, int en, long long S, int used) {
    if(used > k){
        return ;
    }
    if(S > s){
        return;
    }
    if(no > en){
        for(int i = 0; i <= k - used; i++){
            //存下合起来的组合数
            ans += M[i][s-S];
        }
        return;
    }
    dfs2(no + 1, en, S, used);
    dfs2(no + 1, en, S + a[no], used);
    if (a[no] <= 20){
        dfs2(no + 1, en, S + fact[a[no]], used + 1);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> k >> s;
    fact[1] = 1ll;
    //阶乘初始化
    for(int i = 2; i <= 20; i++){
        fact[i] = fact[i - 1] * i;
    }
    for(int i = 1; i <= n; i++){
        cin >> a[i];
    }
    dfs1(1, (n + 1) / 2, 0, 0);
    dfs2((n + 1)/2 + 1, n, 0, 0);
    cout<<ans<<endl;
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值