深入理解OJ编程中的输入输出:11个经典题目详解与技巧分享及stringstream,sort详解


本篇文章将详细介绍在ACM模式下常见的输入输出类型,搞懂这11道题可以帮我们打好算法基础,避免因为最后结果的输出导致无法完成题目。在讲完题目之后再讲两个常用的函数: stringstreamsort


1.多组输入计算a+b

image.png

#include<iostream>
using namespace std;
int main()
{
    int a,b;
    //使用while循环来处理所有输入
    while(cin>>a>>b)
    {
        cout<<a+b<<endl;
    }
    return 0;
}

2.给定组数计算a+b

image.png

#include<iostream>
using namespace std;
int main()
{
    int n;
    cin>>n;
    int a,b;
    while(n--)
    {
        cin>>a>>b;
        cout<<a+b<<endl;
    }
    return 0;
}

3.给定组数计算a+b(如果为0则结束)

image.png

#include<iostream>
using namespace std;
int main()
{
    int a,b;
    while(cin>>a>>b)
    {
       if(a==b&&b==0)
       {
           break;
       }
        cout<<a+b<<endl;
    }
    return 0;
}
  • **while**** 循环** 更适合处理未知数量的输入数据,使用起来更灵活,也是处理这种"无限输入,特定条件结束"的经典方式。
  • **for**** 循环** 在你知道确切的循环次数时使用更为方便,但在这个问题中,因为输入可能是无限的,因此 while 循环会更常用和合适。

4.计算一些列数的和(第一个数为0时结束)

image.png
解法1:

#include<iostream>
using namespace std;

int main() {
    int n;
    while (cin >> n && n != 0) { // 读取整数个数n,且n不为0时进入循环
        int sum = 0, temp;
        for (int i = 0; i < n; i++) { // 循环读取n个整数并求和
            cin >> temp;
            sum += temp;
        }
        cout << sum << endl; // 输出求和结果
    }
    return 0;
}

解法2:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n=0;
    while(cin>>n&&n!=0)
    {
        int sum=0;
        vector<int> arr(n);
        for(int i=0;i<n;i++)
        {
            cin>>arr[i];
            sum+=arr[i];
        }
        cout << sum << endl;
    }
}

5.计算一些列数的和(告诉了有几组)

image.png

#include<iostream>
using namespace std;
int main() {
    int t;
    cin >> t; // 读取数据组数
    while (t--) { // 当t > 0时循环,每次循环处理一组数据
        int n, sum = 0;
        cin >> n; // 读取当前组的整数个数
        for (int i = 0; i < n; i++) { // 循环读取n个正整数并求和
            int temp;
            cin >> temp;
            sum += temp;
        }
        cout << sum << endl; // 输出当前组的和
    }
    return 0;
}

6.计算一系列数的和(不告知几组和何时结束,每一组第一个数为一共本组几个数)

image.png

#include<iostream>
using namespace std;
int main() {
    int n;
    while(cin >> n) {  // 逐行读取每行的第一个整数,即整数的个数
        int sum = 0;
        for(int i = 0; i < n; i++) {
            int num;
            cin >> num;  // 逐个读取正整数
            sum += num;  // 将其加入求和变量
        }
        cout << sum << endl;  // 输出该行的和
    }
    return 0;
}

7.计算一系列数的和(一行一组,不告诉一组几个,需要判断)

image.png
解法1:

#include <iostream>
using namespace std;
int main() {
    int sum = 0;
    int a;
    while (cin >> a) {
        sum += a;
        // 这里用 cin.get() 是换行符来判断,是否到了最后一个数,如果是的话,就把和输出出来,并把 sum 置零
        if (cin.get() == '\n') {
            cout << sum << endl;
            sum = 0;  // 清零以准备下一行
        }
    }
}

解法2:

#include <iostream>
using namespace std;
int main() {
    int a;
    int sum = 0;
    while (scanf("%d", &a) != EOF) {
        sum += a;
        if (getchar() == '\n') {
            printf("%d\n", sum);
            sum = 0;  // 清零以准备下一行
        }
    }
}

解法3:

string line;          // 定义一个字符串变量line,用于存储一行输入
	while (getline(cin, line))  // 循环读取每一行输入
	{
		stringstream ss;  // 创建一个stringstream对象ss
		ss << line;      // 将当前行的输入字符串line放入ss中
		int cur_sum = 0; // 初始化当前行的和cur_sum为0
		int x;           // 定义一个整数变量x,用于存储从ss中读取的每个整数
		// 从ss中读取整数,直到没有更多的整数可读
		while (ss >> x)
			cur_sum += x;  // 将读取到的整数累加到cur_sum中

		cout << cur_sum << endl;  // 输出当前行的和
	}

8.字符串排序(只排一组,告诉有几个)

image.png
解法1:

#include<iostream>
#include<vector>
#include<algorithm>  // std::sort
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<string> strings(n);

    for(int i = 0; i < n; i++) {
        cin >> strings[i];  // 读取 n 个字符串
    }

    sort(strings.begin(), strings.end());  // 对字符串进行排序
    //注意末尾没有空格
	for (int i = 0; i < n - 1; i++)
	{
		cout << s[i] << " ";
	}
	cout << s[n - 1] << endl;
    return 0;
}

解法2:

int n;
	vector<string> strs;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		string str;
		cin >> str;
		strs.push_back(str);
	}
	sort(strs.begin(), strs.end());
    for(int i = 0; i < n; i++) {
        if(i > 0) cout << " ";  // 控制输出格式
        cout << strings[i];
    }
    cout << endl;

9字符串排序(无固定组数)

image.png
解法1:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
    vector<string> words;
    string word;
    
    while (cin >> word) {  // 读取每个单词
        words.push_back(word);
        if (cin.get() == '\n') {  // 检查是否到达行末
            sort(words.begin(), words.end());  // 对单词进行排序
            
            for (size_t i = 0; i < words.size(); ++i) {
                cout << words[i];
                if (i < words.size() - 1) {
                    cout << " ";  // 输出空格,除非是最后一个单词
                }
            }
            cout << endl;  // 换行,处理下一行输入
            words.clear();  // 清空单词列表,准备下一行输入
        }
    }
    return 0;
}

解法2:

string line;  // 用于存储每行输入的字符串

while (getline(cin, line)) {
    stringstream ss(line);  // 使用 stringstream 来处理行内的单词
    vector<string> words;   // 存储当前行的所有单词
    string word;            // 临时变量,用于存储每个单词

    while (ss >> word) {
        words.push_back(word);  // 将提取到的单词存储到 vector 中
    }

    sort(words.begin(), words.end());  // 使用标准库中的 sort 函数对单词进行排序

    for (size_t i = 0; i < words.size() - 1; ++i) {
        cout << words[i] << " ";  // 输出当前单词,并加上空格
    }
    cout << words.back();  // 输出最后一个字符串,不带空格
    cout << endl;  // 换行,处理下一行输入
}

10.字符串排序(输入用逗号分开)

image.png
解法1:

#include <iostream>
#include <vector>
#include <algorithm>
#include <sstream>

using namespace std;

int main() {
    string line;
    while (getline(cin, line)) {  // 读取一行字符串
        vector<string> words;
        string word;
        stringstream ss(line);
        
        while (getline(ss, word, ',')) {  // 读取每个单词,使用逗号作为分隔符
            words.push_back(word);
        }

        // 使用 sort 函数对字符串数组进行排序
        sort(words.begin(), words.end());

        // 输出排序后的字符串
        for (size_t i = 0; i < words.size() - 1; i++) {
            cout << words[i] << ",";  // 输出字符串和逗号
        }
        cout << words.back();  // 输出最后一个字符串,不带逗号
        cout << endl;
    }

    return 0;
}

11.注意数据范围,用 long

image.png

image.png

**注意:**看好数据范围
题目要求处理的整数范围是 0 < a, b < 2 × 10^10。然而,int 类型在大多数 C++ 实现中最多只能表示到 2^31 - 1 (即大约 2.14 × 10^9),这比题目中的最大值要小得多。使用 int 类型来存储输入数据,如果输入的数据非常大,可能会导致整数溢出,进而使结果错误。

正确代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    long long a, b;  // 使用 long long 类型以处理更大的数值范围
    while(cin >> a >> b)
    {
        cout << (a + b) << endl;  // 输出两个大整数的和
    }
    return 0;
}

这道题想要教会我们什么?

  1. 大数处理: 在C++编程中,尤其是在处理大数时,要谨慎选择数据类型。int 类型在面对超大数值时可能会溢出,因此要熟练掌握使用 long long 来处理更大的整数。
  2. 边界条件测试: 你的代码可能在处理样例和小数据时表现良好,但在面对大范围数据时会暴露问题。这提醒你在设计和测试代码时,需要覆盖更广泛的边界条件。
  3. 全面的代码测试: 在面对在线编程题时,不仅要在自己的测试环境下测试,还要注意潜在的极限条件。OJ系统通常会有更全面的测试数据,因此提交前要确保代码在所有可能的条件下都能正常运行。

拓展:longlong long
long 和 long long 是 C++ 中的两种整数数据类型,它们之间主要的区别在于它们能表示的数值范围不同。

  1. long 类型
    在大多数编译器和平台上,long 通常是 4字节(32位),和 int 一样大。
    它的取值范围通常是 -2,147,483,648 到 2,147,483,647,即
    2-31到 231 -1
  1. long long 类型
    long long 是一种较新的类型,通常是 8字节(64位),比 long 能表示更大的整数。
    它的取值范围通常是 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807,即
    -263到263 -1

stringstream详解

stringstream 是 C++ 标准库中的一个非常有用的类,它结合了字符串操作和流操作的功能。stringstream 允许你像处理文件流一样处理字符串,这在很多场合都非常有用,尤其是在算法题中。下面详细介绍 stringstream 的常见用法和在算法题中的使用场景
当然可以!stringstream 是 C++ 标准库中的一个非常有用的类,它结合了字符串操作和流操作的功能。stringstream 允许你像处理文件流一样处理字符串,这在很多场合都非常有用,尤其是在算法题中。下面详细介绍 stringstream 的常见用法和在算法题中的使用场景。

stringstream 类概述

stringstream 类是 <sstream> 头文件的一部分,它继承自 istreamostream,这意味着你可以像使用 cincout 一样使用它来进行输入输出操作。

常见用法

1. 创建 stringstream 对象
#include <sstream>
std::stringstream ss;

2. 向 stringstream 写入数据

你可以使用 << 运算符向 stringstream 写入数据,就像使用 cout 一样:

ss << "Hello, " << 42 << "!";

3. 从 stringstream 读取数据

你可以使用 >> 运算符从 stringstream 读取数据,就像使用 cin 一样:

int num;
ss >> num;  // 读取整数

4. 将 stringstream 转换为字符串

你可以使用 str() 成员函数获取 stringstream 中的内容作为字符串:

std::string str = ss.str();

在算法题中的使用场景

1. 字符串到数字的转换

使用 stringstream 来将字符串转换为数字类型,这对于解析输入非常有用:

#include <iostream>
#include <sstream>
using namespace std;
int main() {
    string input = "12345";
    stringstream ss(input);
    int number;
    ss >> number;
    cout << "Number: " << number << endl;
    return 0;
}

2. 数字到字符串的转换

使用 stringstream 来将数字转换为字符串类型,这对于构建输出非常有用:

#include <iostream>
#include <sstream>

using namespace std;

int main() {
    int number = 12345;
    stringstream ss;
    ss << number;
    string strNumber = ss.str();
    cout << "String: " << strNumber << endl;
    return 0;
}

3. 字符串分割

使用 getlinestringstream 来分割字符串,这对于处理 CSV 或其他分隔符分隔的数据非常有用:

#include <iostream>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

int main() {
    string line = "a,c,bb";
    vector<string> words;
    string word;
    stringstream ss(line);
    
    while (getline(ss, word, ',')) {  // 读取每个单词,使用逗号作为分隔符
        words.push_back(word);
    }

    // 输出排序后的字符串
    for (size_t i = 0; i < words.size() - 1; i++) {
        cout << words[i] << ",";  // 输出字符串和逗号
    }
    cout << words.back();  // 输出最后一个字符串,不带逗号
    cout << endl;

    return 0;
}

getline(ss,word,‘,’)
** 在 C++ 中,getline 是一个用于从输入流中读取一行字符串的函数,它也可以从 stringstream 这样的流中读取。getline 的第三个参数允许你指定一个分隔符,这样你可以按分隔符来读取数据,而不仅仅是到换行符为止。
**getline(ss, word, ',')**
的含义是从 **stringstream** 对象 **ss** 中读取字符到字符串 **word**,直到遇到指定的分隔符 **,** 为止,或者到达流的结尾。**
下面是这行代码的各个参数的具体含义:

  • **ss**: 输入流对象,这里是 **stringstream**
  • **word**: 用于存储读取到的字符串。
  • **,**: 分隔符,表示在读取过程中遇到的逗号 **,** 会作为分隔符,读取到逗号时停止读取,逗号不会包括在读取到的字符串中。

假设我们有以下的输入流内容 **ss**,它是一个 **stringstream** 对象,内容如下:

apple,banana,orange,grape

以下是几种情况下的 getline(ss, word, ',') 的行为示例:
示例 1代码:

getline(ss, word, ',');
cout << word << endl;

结果:

apple

解释:第一次调用 getline(ss, word, ',') 会读取到第一个逗号 , 之前的内容 apple,并将其存储到 word 中。然后输出 apple
示例 2代码:

getline(ss, word, ',');
getline(ss, word, ',');
cout << word << endl;

结果:

banana

解释:第一次调用 getline(ss, word, ',') 会读取 apple。第二次调用 getline(ss, word, ',') 会读取 banana,直到下一个逗号 , 为止。然后输出 banana
示例3:代码:

getline(ss, word, ',');
getline(ss, word, ',');
getline(ss, word, ',');
cout << word << endl;

结果:

orange

解释:第一次调用 getline(ss, word, ',') 读取 apple。第二次调用读取 banana。第三次调用读取 orange。此时 ss 的下一个内容是 grape。所以 word 变为 orange,输出 orange
示例 4代码:

getline(ss, word, ',');
getline(ss, word, ',');
getline(ss, word, ',');
getline(ss, word, ',');
cout << word << endl;

结果:

grape

解释:前三次调用分别读取 applebananaorange。最后一次调用读取到 grape,并且遇到流的结尾,grape 是最后一个单词。输出 grape

总结:
getline(ss, word, ',') 用于按逗号分隔读取输入流中的字符串,这在处理用特定字符分隔的数据时非常有用。每次调用 getline 都会读取到下一个分隔符之前的内容,并将其存储到 word 变量中。

4. 读取和写入数据

std::stringstream 结合了 std::istringstreamstd::ostringstream 的功能,既可以从字符串中读取数据,也可以将数据写入字符串。
示例:读取和写入数据

#include <iostream>
#include <sstream>

using namespace std;

int main() {
    stringstream ss;  // 创建字符串流

    ss << "123 456 78.9";  // 将数据写入字符串流

    int a, b;
    float c;

    ss >> a >> b >> c;  // 从字符串流中读取数据

    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    cout << "c = " << c << endl;

    return 0;
}

在这个例子中,stringstream 同时用作输入和输出流。
stringstream 是一个非常强大的工具,它可以帮助你在字符串操作方面更加灵活。它不仅可以在字符串和数字之间进行转换,还可以用于解析和构造字符串,甚至用于模拟文件输入输出。希望这些示例对你有所帮助!如果有任何其他问题,请随时提问。

sort详解

std::sort 是 C++ 标准库中的一个排序算法,用于对容器中的元素进行排序。它位于 <algorithm> 头文件中,并且通常用于对 std::vectorstd::arraystd::deque 等容器的元素进行排序。它采用了高效的排序算法(通常是快速排序,但在某些实现中可能会使用其他算法,如堆排序(HeapSort)或插入排序(Insertion Sort))。以下是对 std::sort 的全面讲解,包括其用法、典型场景、以及代码示例。

1. 函数原型

std::sort 的基本原型如下:

template<class RandomAccessIterator>
void sort(RandomAccessIterator first, RandomAccessIterator last);

template<class RandomAccessIterator, class Compare>
void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
  • **Compare** 是一个比较函数或仿函数(functor),定义了元素之间的比较逻辑。
  • **RandomAccessIterator**: 这是指向容器中元素的随机访问迭代器类型。
  • **first**: 这是指向待排序序列的第一个元素的迭代器。
  • **last**: 这是指向待排序序列的最后一个元素之后的位置的迭代器。
2. 排序的时间复杂度

std::sort 的时间复杂度通常为 O(n log n),其中 n 是待排序元素的数量。这个复杂度使其在大多数情况下都表现出色。尽管最坏情况下的复杂度可能达到 O(n^2),但实际应用中,快速排序通常提供了相当稳定的性能。

3. 使用场景

std::sort 适用于各种需要排序的场景,包括但不限于:

  • 对数组、向量或其他容器中的元素进行排序。
  • 对某个结构体的数组进行排序,可以通过自定义比较函数来实现复杂排序需求。
  • 在需要对算法中的数据进行排序以提高效率时。
4. 常见用法

4.1. 对数组进行排序

以下是对数组进行排序的示例:

#include <iostream>
#include <algorithm> // 引入 sort 函数
using namespace std;

int main() {
    int arr[] = {5, 2, 9, 1, 5, 6}; // 定义一个整数数组
    int n = sizeof(arr)/sizeof(arr[0]); // 计算数组大小

    // 对数组进行排序
    sort(arr, arr + n);

    // 输出排序后的数组
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " "; // 打印每个元素
    }
    cout << endl;

    return 0;
}

4.2. 对 std::vector 进行排序

以下是对 std::vector 进行排序的示例:

#include <iostream>
#include <vector>
#include <algorithm> // 引入 sort 函数
using namespace std;

int main() {
    vector<int> vec = {10, 5, 8, 1, 2}; // 定义一个整数向量
    // 对向量进行排序
    sort(vec.begin(), vec.end());
    // 输出排序后的向量
    for (int num : vec) {
        cout << num << " "; // 打印每个元素
    }
    cout << endl;
    return 0;
}

4.3. 自定义排序规则

可以通过传递一个自定义比较函数或函数对象来改变排序的规则。例如,按降序排序:

#include <iostream>
#include <vector>
#include <algorithm> // 引入 sort 函数
using namespace std;

// 自定义比较函数,用于降序排序
bool compare(int a, int b) {
    return a > b;
}

int main() {
    vector<int> vec = {10, 5, 8, 1, 2}; // 定义一个整数向量

    // 对向量进行降序排序
    sort(vec.begin(), vec.end(), compare);

    // 输出排序后的向量
    for (int num : vec) {
        cout << num << " "; // 打印每个元素
    }
    cout << endl;

    return 0;
}

4.4. 对结构体进行排序

假设我们有一个结构体 Person,按年龄排序:

#include <iostream>
#include <vector>
#include <algorithm> // 引入 sort 函数
using namespace std;

struct Person {
    string name;
    int age;
};

// 自定义比较函数,用于按年龄排序
bool compareByAge(const Person& a, const Person& b) {
    return a.age < b.age;
}

int main() {
    vector<Person> people = {{"Alice", 30}, {"Bob", 25}, {"Charlie", 35}}; // 定义一个 Person 向量

    // 对向量中的 Person 进行排序,按年龄
    sort(people.begin(), people.end(), compareByAge);

    // 输出排序后的向量
    for (const Person& p : people) {
        cout << p.name << " (" << p.age << ") "; // 打印每个 Person 的信息
    }
    cout << endl;

    return 0;
}

4.5. 部分排序

可以对容器的部分区域进行排序:

#include <iostream>
#include <vector>
#include <algorithm> // 引入 sort 函数
using namespace std;

int main() {
    vector<int> vec = {10, 5, 8, 1, 2}; // 定义一个整数向量

    // 对向量的部分区域进行排序
    sort(vec.begin() + 1, vec.end() - 1);

    // 输出排序后的向量
    for (int num : vec) {
        cout << num << " "; // 打印每个元素
    }
    cout << endl;

    return 0;
}

好的,接着上面的讲解,我们来看一下如何使用比较函数对象来自定义排序逻辑。

4.6 使用比较函数对象

在C++中,sort函数除了能够进行默认的升序排序外,还允许我们通过提供比较函数对象来自定义排序规则。比较函数对象是可以作为函数使用的类或结构体的实例,它能够根据我们定义的逻辑对元素进行比较。

4.6.1 greater<int>函数对象

greater<int>是标准库中的一个函数对象,用于实现降序排序greater模板类是定义在<functional>头文件中的,它的作用是对两个对象进行“大于”比较。
示例代码:

#include <iostream>
#include <vector>
#include <algorithm>  // 包含sort函数的头文件
#include <functional> // 包含greater的头文件

using namespace std;

int main() {
    // 创建一个包含整数的向量
    vector<int> v = {3, 1, 4, 1, 5};

    // 使用sort函数对向量进行排序,并使用greater<int>()作为比较函数对象,实现降序排序
    sort(v.begin(), v.end(), greater<int>());

    // 输出排序后的向量
    for (int i : v) {
        cout << i << " ";  // 依次输出每个元素
    }

    return 0;
}

输出:

5 4 3 1 1

4.6.2 其他常见的函数对象

除了greater外,C++标准库还提供了其他常见的函数对象,例如:

  • less<T>:用于实现升序排序(默认行为)。
  • greater_equal<T>:用于实现“大于等于”比较。
  • less_equal<T>:用于实现“小于等于”比较。

这些函数对象可以直接用于sort函数中,帮助我们根据不同的需求定制排序规则。

4.6.3 自定义函数对象

除了使用标准库提供的函数对象外,C++还允许我们自定义比较函数对象。例如,我们可以创建一个函数对象来实现按字符串长度排序。
示例代码:

#include <iostream>
#include <vector>
#include <algorithm>  // 包含sort函数的头文件

using namespace std;

// 自定义函数对象,用于按字符串长度排序
struct LengthCompare {
    bool operator()(const string &a, const string &b) const {
        return a.length() < b.length();  // 返回a是否小于b
    }
};

int main() {
    // 创建一个包含字符串的向量
    vector<string> v = {"apple", "banana", "pear", "grape"};

    // 使用sort函数,并传入自定义的比较函数对象LengthCompare
    sort(v.begin(), v.end(), LengthCompare());

    // 输出排序后的向量
    for (const string &s : v) {
        cout << s << " ";  // 依次输出每个字符串
    }

    return 0;
}

输出:

pear grape apple banana

在这个例子中,我们定义了一个名为LengthCompare的函数对象,用于按字符串的长度进行排序。sort函数会使用我们提供的逻辑来决定排序顺序。

5. 注意事项
  • std::sort 要求排序的范围必须是随机访问迭代器,因此它适用于 std::vector、数组等支持随机访问的容器。对于其他类型的容器(如链表),请使用其他排序算法,如 std::listsort 成员函数。
  • 确保提供的比较函数是严格弱序的,即对于任意元素 a, b, c,如果 a < bb < c,则必须有 a < c
  • 自定义比较函数必须满足这一特性,否则排序结果可能不正确。
6. 总结

std::sort 是 C++ 中一个功能强大且常用的排序算法。它适用于多种场景,包括对基本类型、用户自定义类型进行排序,以及对部分数据进行排序。通过自定义比较函数,可以灵活地控制排序的行为,以适应不同的需求。希望这个详细的讲解能帮助你更好地理解和应用 std::sort


07c03ae6d77b4b153f6d1ec710be7c14_7a80245f0b5f4021a033b3789a9efdeb.png

  1. 📜 [ 声明 ] 由于作者水平有限,本文有错误和不准确之处在所难免,
  2. 本人也很想知道这些错误,恳望读者批评指正!
  3. 我是:勇敢滴勇~感谢大家的支持!
评论 120
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值