一维数组及其应用

考虑这样一个问题:读入一些整数,逆序输出到一行中。已知整数不超过100个。如何编写这个程序呢?首先是循环读取输入。读入每个整数以后,应该做些什么呢?思来想去, 在所有整数全部读完之前,似乎没有其他事可做。换句话说,只能把每个数都存下来。那么存放在哪里呢?答案是:数组。

(一)一维数组的定义和引用

定义:数组是有序的元素序列,是有限个类型相同的变量的集合。

1.一维数组的定义

类型标识符 数组名[常量表达式];

类型标识符数组名常量表达式
int float double char bool string…必须是合法的标识符,C++语言规定只能由字母或下划线开头,可以由字母或数组组成常量表达式的值即为数组元素的个数,下标从0~n-1。对于传统的C数组,要求是整型常量表达式。

如:int num[10];
就定义了一个一维整型数组,数组名为num,数组中的元素为10个,分别为num[0]、num[1] 、num[2]… num[9]。同一数组的所有数组元素在内存中占用一片连续的存储单元。
在这里插入图片描述

注:
(1)数组中的变量称为数组元素,数组元素都有下标,数组元素也称下标变量。元素下标从0开始,使用数组时下标不能越界,否则会造成内存的混乱,可导致不可预测的错误。如下面这段程序:

#include<bits/stdc++.h>
using namespace std;
int main() {
	int a[10];
	for(int i=1;i<15;i++){
		a[i]=0;
		cout<<i;
	}
	return 0;
}

(2)数组中的每个元素都属于同一类型,数组元素可以是基本数据类型或是构造类型。如:

float score[100]; 
bool sex[100];
string name[100];

(3)用方括号括起来的常量表达式的值是一个非负整数,表示数组元素的个数即数组长度,如下面的写法是合法的:

int a[10];//a[0]是第一个元素,a[9]是最后一个元素 
char sum[10000+5];
int n=100;
int sum[n*2];

(4)局部数组默认值为野值,全局数组默认值为0。大数组须定义为全局数组,在局部定义大数组会爆栈(详见文档最后解析)
(5)根据2022年CSP比赛内存512M,我们可以算出可定义的不同类型的最大数组大小:
512 M = 512 ∗ 1024 ∗ 1024 B y t e = 536870912 c h a r = 134217728 i n t = 67108864 d o u b l e 512 M = 512*1024*1024 Byte = 536870912 char= 134217728 int=67108864 double 512M=51210241024Byte=536870912char=134217728int=67108864double

2.一维数组元素的引用

数组与变量一样必须先定义,然后才可使用。只能逐个引用数组元素的值,而不能一次引用整个数组中全部元素的值。
数组元素的表示形式为:
数组名[下标]
注意:下标的值必须为整型,值从0开始,最大值为数组长度减1。
例如,可以像下面这样引用:
a[0]、sum[i]、a[b[i]]、score[i+1]
当然表达式i、b[i]、i+1的值必须在对应的数组下标范围之内。

如果int a[100],b[100];
表达式“a>b"在C++中是不支持的,C++中不能一次引用整个数组;但可以比较a[2]和b[2]的大小,我们可以写成:a[2] >b[2]。如执行这样的语句:“cout <<a[100]<<endl;”,虽然我们没有定义a[100]元素,但C++不会检测下标越界问题,所以能通过编译,运行时会导致不可预料的结果。这种错误我们在编程时要注意避免。

3.一维数组的存锗

数组定义后,对应着一块连续的内存单元,其地址与容量在程运行后到程序结束前保持不变,数组在计算机内存单元中是连续存储的。例如,定义数组bool vis[20];如果数组vis的起始地址为P,由于bool类型占用1个字节,则vis[1]的起始地位为P+1,vs[2]的起始地位为P+2…,vs[19]的起始地位为P+19。如果定义数组int vis[20];,vis定义为int类型,由于int类型占用4个字节,则vs[1]的起始地址为P+4,vis[2]的起始地址为P+8…,vis[19]的起始地址为 P+76。

数组定义后,就可以计算出整个数组所占的存储空间大小。数组所占用的空间为:单个数组元素所占用的空间(如int类型为4个字节,char类型为1个字节)乘以数组元素个数,这样算出来的存储空间的单位是字节。当然我们也可以直接用函数sizeof(数组名)来求出整个数组所占用的存储空间。如“int a[100];”,可以这样计算: 4 ∗ 100 = 400 字节 4*100=400字节 4100=400字节,也可以用 sizeof(a)来计算。

(二)一维数组的赋值

数组定义后,需要给数组元素赋值,我可用下种方法给数组元素赋值

1、定义数组时赋值

C++中,单个变量的值可以在定义时同时赋值,数组也可以在定义时赋值。
表5.2-1定义时给数组元素赋值

语句作用
int a[1005]如果这条语句定义在主函数之上,则数组a所有元素的值赋为0
int a[5]={1,2,3,4.5};a[0]、a[1]、a[2]、[3]、a[4]的值分别赋为1,2,3,4,5
int a[5]={1,2,3};a[0]、a[1]、a[2]、[3]、a[4]的值分别赋为1,2,3,0,0
int a[5]={0};将数组a中5个元素的值全赋为0
int a[]={1,2,3};a[0]、a[1]、a[2]的值分别赋为1,2,3,且将数组的长度定义为3

2、用函数赋值

C语言的数组并不是“一等公民”,而是“受歧视”的。例如,数组不能够进行赋值操作:
如声明“int a[maxn],b[maxn]”,是不能赋值b=a的。

C++提供的memset、memcpy、fill函数都可以给数组元素赋值。
memset函数按字节对内存块进行初始化,通常用来将数组每个元素的值初始化为0或-1。memcpy函数可以将指定的一段内存地址中储存的内容,拷贝到另一段连续的地址中,所以通常用来将一个数组的值赋给另一个数组。这两个函数使用前都必须引用头文件。fill 函数也可以用来对数组元素赋值,使用前需引用头文件。

语句作用
memset(a,true,sizeof(a));给bool类型数组 a 每个元索都赋值为true
memset(a,true,3);相当于语句for(int i=0;i<3;i++) a[i]= true;
memset(ch,97,sizeof(ch));给字符数组ch每个元索赋值为字符’a’
memset(a,-1,sizeof(a));即给数组a的每个元素的每个字节赋值为-1的补码为(11111111)2即-1
fill(a,a+4,4);相当于语句for(int i=0;i<4;i++) a[i]= 4;
memcpy(b,a,sizeof(int)*k);从数组a复制k个元素到数组b;当然,如果数组a和b都是浮点型double,复制时要写成memcpy(b,a,sizeof(double)*k)
memcpy(b,a,sizeof(a));把数组a全部复制到数组b

3、用输入语句逐个赋值

例如:

int x[100],y[100];
for(int i=0;i<100;i++)
	cin>>x[i];
for(int i=0;i<100;i++)
	scanf("%d",&y[i]);

注意:数组元素输出时,也只能逐个输出。如:

int x[100];
for(int i=0;i<100;i++)
	cout<< x[i];//用循环语句批量输出数组元素
cout<<x[50]<<endl;//输出单个数组元素

不能写为:cout << x<< endl;

习题1:逆序输出

回到我们上课开始的问题:
读入一些整数,逆序输出到一行中。已知整数不超过100个。

#include<stdio.h>
#define maxn 105//在空间够用的情况下数组一般会声明得稍大一些防止越界
int a[maxn];
int main(){
	int x,n=0;
	while(scanf("%d",&x)==1) //scanf的返回值为读入元素的个数,以ctrl+z两个字符结束输入
		a[n++]=x;			//相当于a[n]=x;n++;
	for(int i=n-1;i>=1;i--)
		printf("%d ",a[i]);
	printf("%d\n",a[0]);
	return 0;
}

注:现在的题目中一般会说明输入元素的个数,故无需使用scanf("%d",&x)==1

4、在程序中用赋值语句逐个赋值

例如:

int x[100],y[100];
for(int i=0;i<100;i++)
	x[i]=i*i;
for(int j=0;j<100;j++)
	y[j]=j*j*j; 

习题2:斐波那契数列

运行下面程序思考该程序运行后的输出结果。

#include<bits/stdc++.h>
using namespace std;
int a[40]={1,1};//定义时给a[0]、a[1]赋值为1,其他数组元素赋为0
int main(){
    int n;
    cin>>n;
	for(int i=2;i<n;i++) 
		a[i]=a[i-1]+a[i-2];//用赋值语句给数组元素逐个赋值
	for(int i=0;i<n-1;i++) //顺序输出数组中元素的值 
		cout<<a[i]<<" ";
	cout<<a[n-1]<<endl;
	return 0;
}

程序输出:1 1 2 3 5 8
【问题分析】
数组opt第1个元素为1,第2个元素为1,从第3个元素开始,每个元素皆为前两个元素之和。所以数组 opt 保存的就是斐波那契数列:1、1、2、3、5、8…

习题3:进制转换

【例2】进制转换
【问题描述】
给定一个十进制正整数N,求其对应的二进制数。
【输入格式】
仅一行,包含一个正整数N。
【输出格式】
共一行,包含一个正整数,表示N对应的二进制数。
【输入样例】
10
【输出样例】
1010
【数据范围】
1≤N≤30000
【问题分析】
十进制整数转换为二进制整数采用“除2倒序取余”法。具体做法是用2除十进整 数,可以得到一个商和余数;再用2去除商,又会得到一个商和余数,如此进行,直到商为0时为止,然后把得到的余数倒序输出。
【参考程序】

#include<bits/stdc++.h>
using namespace std;
int n,num[100],t;
int main(){
	cin>>n;
	while(n){
		t++; 
		num[t]=n%2;//用数组num 保存每次的余数 
		n/=2; 
	}
	for(int i=t;i>=1;i--)//例序输出数组中元素 
		cout<<num[i]; 
	cout<<endl; 
	return 0;
}

课后练习

习题4:走楼梯

【题目描述】
一个楼梯有 n 级,小文同学从下往上走,每一步可以跨一步,也可以跨两步。问:走到第 n 级台阶有多少种走法?
【输入格式】
一个一个整数 n,0<n<=30。
【输出格式】
一行 n 个整数,之间用一个空格分隔,表示走到第1级、第2级…第n级台阶分别有多少种走法。
【输入样例】
2
【输出样例】
1 2

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n,f[31];
	scanf("%d",&n);
	f[1]=1;f[2]=2;
	for(int i=3;i<=n;i++)
		f[i]=f[i-1]+f[i-2];
	for(int i=1;i<n;i++)
		cout<<f[i]<<" ";
	cout<<f[n];
	return 0;
}

习题5:火柴数字

【题目描述】
火柴数字如下图:
在这里插入图片描述
现用n根火柴摆数字,请列出所有能摆出的自然数,要求每个数火柴全用上,不多不少。

【输入格式】
一个整数 n,0<n<=10。
【输出格式】
所有能摆出的自然数,用空格分隔
【输入样例】
6
【输出样例】
0 6 9 14 41 77 111

【问题分析】
0~9每根所用的火柴棒数量:

数字0123456789
火柴棒6255456376

可以看出:1最少,用了2根,8最多,用了7根。不难分析出数字范围是[0,11111]之间。
思考7根火柴棒的范围?[8,711] 18根火柴?
知道了数据范围,且每个数需使用n根火柴的条件明确,此时我们可以考虑使用穷举法:将[0,11111]的每个数的所使用的总火柴数统计,若为n则输出。
算法:通过循环列出 [0,11111] 的每个数,再写一个内层循环判定每个数所使用的的火柴个数(与上面的数字统计类似),整体上是一个双层循环。外层从0取到11111,内层把每个数的每一位所使用火柴数的和算出来,0~9十个数字的火柴数可以用数组来表示。参考程序如下:

#include<bits/stdc++.h>
using namespace std;
int a[]={6,2,5,5,4,5,6,3,7,6};//0~9分别需要多少根火柴棒
int main(){
	int n;
	cin>>n;
	if(n==6)
		cout<<0<<" ";
	for(int i=1;i<=11111;i++){//穷举范围
		int s=0;		//统计总数目
		int ti=i;	//因i会在内层循环时发生改变,在此对i进行保存以便后续使用
		while(ti){ //计算ti需要多少根火柴棒,ti非0才会执行循环,所以0不在计算范围
			s=s+a[ti%10];	//个位所用的数量
			ti=ti/10; 	//整除10,除去个位数
		}
		if(s==n)
			cout<<i<<" ";
	}
	return 0;
}

(三)一维数组的查询、统计

1、查询

顺序查找:本质即从数组的第一个位置找到最后一个位置,判断是否有所需特定数值x。
【参考代码】

for(int i=1;i<=n;i++)
	if(a[i]==x){
		ans=i;
		break;
	}

习题6:二分查找

如果数组中元素是有序的(从小到大或从大到小),我们可以用二分查找来提高效率。
二分查找:假定数组有小到大排列,首先将数组中间位置上的元素与x进行比较,如果x大于中间位置元素,则在数组右半部分继续进行二分查找;否则在左半部分继续二分查找。
【参考代码】

	int ans=-1;//假定数组中没有x这个数
	int l=1,r=n;//l和r表示查找范围,初始范围为数组1~n元素
	while(l<=r){//有区域可查找
		int mid=(l+r)/2;
		if(a[mid]==x){//找到x
			ans=mid;
			break;
		}
		if(g<a[mid])
			r=mid-1;//在左半部分查找
		else
			l=mid+1;//在右半部分查找
	}	

还可以通过C++中的函数方便地实现查找
lower_bound(begin,end,num)
upper_bound(begin,end,num)
binary_search(begin,end,num)

2、统计

通过访问数组每一个元素,统计某一个值或数组元素符合某一条件的次数

桶排序

当数组元素的值范围较小时我们可以使用桶排序。
方法:定义一个数组a,用a[i]表示值为i的元素有多少个。输出时依次访问a[1]到a[n],当a[i]不为0时输出a[i]个i,从而实现排序功能。

习题7:桶排序

	for(int i=1;i<=n;i++){
		cin>>x;
		a[x]++;
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=a[i];j++)
			cout<<i<<" ";

(四)一维数组元素的移动

1、数组部分元素整体左移

习题8:删除元素

【输入样例】
10
100 200 150 140 129 134 167 198 200 110
【输出样例】
100 150 140 129 134 167 198 110
【样例解释】
删除最大值
【参考程序】

#include<bits/stdc++.h>
using namespace std;
int n,a[10000],m,cnt;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		m=max(m,a[i]);
	}
	for(int i=1;i<=n;i++){
		while(a[i]==m){
			for(int j=i;j<=n;j++)
				a[j]=a[j+1];//从i位开始,用后一个元素值覆盖前一个元素的值,相当于删除第i个元素
			cnt++;//删除后数组长度缩短,需记缩短的长度,在输出时调整数组长度
		}
	}
	for(int i=1;i<=n-cnt;i++)//注意数组最后两个元素的值完全相同
		cout<<a[i]<<" ";
	return 0;
}

注意:我们在编程时也可以将要删除的元素设置一个删除标志(通常赋值为一个特殊的数),访问时遇到标志则跳过,就不需要左移数组删除元素了。
【参考代码】

#include<bits/stdc++.h>
using namespace std;
int n,a[10000],m;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		m=max(m,a[i]);
	}
	for(int i=1;i<=n;i++){
		if(a[i]==m){
			a[i]=-1;
		}
	}
	for(int i=1;i<=n;i++)
		if(a[i]!=-1)
			cout<<a[i]<<" ";
	return 0;
}

2、数组部分元素整体右移

习题9:插入元素

【输入样例】
10
100 200 150 140 129 134 167 198 200 110
3 120
【输出样例】
100 200 120 150 140 129 134 167 198 200 110
【样例解释】
在第3个位置插入120
【参考程序】

#include<bits/stdc++.h>
using namespace std;
int n,a[10000],b,c;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	cin>>b>>c;
	for(int i=n;i>=b;i--)
		a[i+1]=a[i];
	a[b]=c;//在b处插入c 
	n++;//修改数组长度 
	for(int i=1;i<=n;i++)
		cout<<a[i]<<" ";
	return 0;
}

习题10:插入排序

根据数组下标由小到大依次给数组赋值时,第一个元素直接赋值;给后面的元素x赋值时首先找到第一个比它大的元素y的位置,从y起所有元素右移一位,将x插入到原来y的位置。
【输入样例】
10
100 200 150 140 129 134 167 198 200 110
【输出样例】
100 110 129 134 140 150 167 198 200 200

#include<bits/stdc++.h>
using namespace std;
int n,j,a[10000],b,c;
int main(){
	cin>>n;
	cin>>a[1]; 
	for(int i=2;i<=n;i++){
		cin>>a[0];//输入下一个元素准备插入
		for(j=1;j<i;j++)//从前往后找到第一个比a[0]大的元素,位置存在j中
			if(a[j]>=a[0])
				break;
		for(int k=i;k>=j;k--)//从i到j位置的元素右移一位
			a[k+1]=a[k];
		a[j]=a[0];//插入新的元素 
	}
	for(int i=1;i<=n;i++)
		cout<<a[i]<<" ";
	return 0;
}

3、两个数组元素相互移动

swap(a,b)可以实现两个变量值的交换

(1)选择排序

有数组int a={5,2,4,3,1},现对其进行从小到大排序:
第1轮:用a[0]与a[1]~a[4]进行比较,如a[0]大于后面的元素则swap交换
第2轮:用a[1]与a[2]~a[4]进行比较,如a[1]大于后面的元素则swap交换
第3轮:用a[2]与a[3]~a[4]进行比较,如a[2]大于后面的元素则swap交换
第4轮:用a[3]与a[4]进行比较,如a[3]大于后面的元素则swap交换
则代码如下:

习题11:选择排序

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int a[5]={5,2,4,3,1};
	for(int i=0;i<4;i++){			//i除了表示比较的轮次,亦可以表示“擂主”
		for(int j=i+1;j<5;j++){		//j除了表示比较每一轮比较的次数,亦可以表示“打擂者”
			if(a[i]>a[j])
				swap(a[i],a[j]);
		}
	}
	for(int i=0;i<5;i++)
		cout << a[i] << " ";
  	return 0;
}

(2)冒泡排序

有数组int a={5,2,4,3,1},现对其进行从小到大排序:
第1轮:用a[4]与a[3]、a[3]与a[2]、a[2]与a[1]、a[1]与a[0]进行比较,如后者小于前者则swap交换
第2轮:用a[4]与a[3]、a[3]与a[2]、a[2]与a[1]进行比较,如后者小于前者则swap交换
第3轮:用a[4]与a[3]、a[3]与a[2]进行比较,如后者小于前者则swap交换
第4轮:用a[4]与a[3]进行比较,如后者小于前者则swap交换
则代码如下:

习题12:冒泡排序

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int a[5]={5,2,4,3,1};
	for(int i=1;i<5;i++){			//i表示轮次
		for(int j=4;j>=i;j--){		//j除了表示比较每一轮比较的次数,亦可以表示“后者”
			if(a[j]<a[j-1])
				swap(a[j],a[j-1]);
		}
	}
	for(int i=0;i<5;i++)
		cout << a[i] << " ";
  	return 0;
}

快速排序

在这里插入图片描述

习题13:约瑟夫问题

n个人围成一圈,初始编号从1~n排列,从约定编号为1的人开始报数,数到第m个人出圈,接着又从1开始报数,报到第m个数的人又退出圈,以此类推,最后圈内只剩下一个人,这个人就是赢家,求出赢家的编号。
数组模拟
模拟思路简单,但是编码却没那么简单,临界条件特别多,每次遍历到数组最后一个元素的时候,还得重新设置下标为 0,并且遍历的时候还得判断该元素时候是否是 -1。用这种数组的方式做,千万不要觉得很简单,编码这个过程还是挺考验人的。
这种做法的时间复杂度是 O(n * m), 空间复杂度是 O(n);

#include<algorithm>
#include<iostream>
using namespace std;
int main(){
	int a[1001]={0}; //初始化化数组作为环
	int n,m;//n代表总的人数,m代表报数到几退出
	cin>>n>>m;
	int count=0;//记录退出的个数
	int k=-1;//这里假定开始为第一个人,下标为0,编号为1,如需从编号x开始,则k=x-2
	while(count<n-1){  //总共需要退出n-1个人
		int i=0;//记录当前报数编号
		while(i<m){
			k=(k+1)%n; //循环处理下标
			if(a[k]==0){
				i++;
				if(i==m){
					a[k]=-1;
					count++;
				}
			}
		}
	}
	for(int i=0;i<n;i++){
		if(a[i]==0){
			printf("%d\n",i+1);
			break;
		}
	}
	return 0;
}

课后练习:

习题14:陶陶摘苹果(NOIP2005普及组)

习题15:校门外的树(NOIP2005普及组)

习题16:开灯

习题17:质因子分解

(附)数组放在main函数内外的区别

区别一:函数内数组初始值为野值,全局数组初始值为0。
区别二:
我们首先来看一个问题
【问题描述】
给定数列 1, 1, 1, 3, 5, 9, 17, …,从第 4 项开始,每项都是前 3 项的和。求第 20221102 项的最后4位数字。
显然,这题目思路明确清晰,就是不断计算然后对10000进行模运算得到最后4位整数
【错误代码】

#include<iostream>
using namespace std;
const int MOD=10000;
int main(){
	int a[20221110]={0,1,1,1};//a[0]为0,使得下标与序号一致 
	for(int i=4;i<=20221102;i++){
		a[i]=(a[i-3]+a[i-2]+a[i-1])%MOD;
	}
	cout<<a[20221102];
	return 0;

运行后会报错,原因是:
大数组不能放在main函数里面,要定义在main函数外面成为全局变量!

【正确代码】

#include<iostream>
using namespace std;
const int MOD=10000;
int a[20221110]={0,1,1,1};//a[0]为0,使得下标与序号一致
int main(){ 
	for(int i=4;i<=20221102;i++){
		a[i]=(a[i-3]+a[i-2]+a[i-1])%MOD;
	}
	cout<<a[20221102];
	return 0;
}

为什么大数组一定要放在main函数外面而不能放在里面呢?

原因在于开设数组的区域不同,在运行代码的时候,操作系统会分配不同的内存区域来运行代码

栈区:由操作系统自动分配释放,存放函数的参数值,局部变量的值,不需要时系统会自动清除,内存较小
堆区:由new分配的内存块,也就是说在代码中new一个数组,内存由堆区分配;堆区不由编译器管,由应用程序控制,相当于程序员控制。如果程序员没有释放掉,程序结束后,操作系统会自动回收
数据区:也称全局区或者静态区,存放全局的东西,比如全局变量,内存较大
代码区:存放执行代码的地方

简而言之,在main函数外面开设一个数组,它的内存分配在数据区里;而如果在main函数内部开设一个数组,它的内存分配在栈区内。一般来说栈区的内存是比较小的,所以平常开一些小一点的数组是完全没问题的;但如果题目要求的数组比较大,那就会出现爆满溢出的情况,程序将无法访问内存而出错;相反,数据区的内存较大,就不会出现这样的问题。这就是为什么开设大数组一定要放在main函数之外的原因。

约瑟夫问题

#include<bits/stdc++.h>
using namespace std;
int main(){
	int m,n,i=0,j=0,t;
	bool p[100];
	cin>>m>>n;
	for(int i=0;i<100;i++) p[i]=true;
	t=m;
	while(t>0){
		i++;
		if(i==m+1) i=1;//实现圈的效果
		if(p[i]){
			j++;
			if(j==n){
				cout<<i<<endl;
				p[i]=false;
				j=0;
				t--;
			}
		} 
	}
	return 0;
}
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

以太以北

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值