算法基础课02:高精度、前缀和与差分

1.高精度

只有C/C++需要高精度,因为C/C++中无大整数类。当需要对比较大的整数进行四则运算时,没有合适的数据类型。对此,C/C++中遇到大整数运算只能将数字每一位存到数组中。

一般来说高精度常考4种:

(1)两个比较大的整数相加:A + B;

(2)两个比较大的整数相减:A - B;

(3)一个大的整数乘一个小的整数(低精度):A × a;

(4)一个大的整数除以一个小的整数(低精度):A ÷ b。

两个大整数相乘和相除用得不多。其中大整数A、B的位数约为10^6,a的数值10^4(并不是很严格)。

1.1高精度加法

 理解两个问题是理解大整数加法的关键:

①大整数如何存储:将大整数每一位存到数组中,数字低位在前,高位在后(即从数字的个位开始存)。

原因是两个整数相加可能会涉及进位,需要在高位补。而在数组末尾补上一个数很容易;若按照书写习惯数字高位在前低位在后,就需要在数组开头补一个数,这就必须移动整个数组。

② 大整数运算:模拟人工加法,即各位数相加后再加上上一位的进位(如果有的话),并向更高位产生进位(如果有的话)。

C++代码模板

vector<int> add(vector<int> &A , vector<int> &B)			//加引用是为了提高效率,若不加引用就要把整个数组拷贝一遍
{
	vector<int> C;											//声明答案 C

	int t = 0;												//定义上一位进位 t , 初始为 0
	for(int i = 0; i < A.size() || i < B.size(); i ++)		
	{														//用 t 来表示 A[i] 、B[i]和上一位进位位的和
		if(i < A.size()) t += A[i];							//如果 i 没有超过 A 的范围,那么 t = 上一位进位位 t + A[i]
		if(i < B.size()) t += B[i];							//如果 i 没有超过 B 的范围,那么 t = 上一位进位位 t + B[i]
/*若两个if()判断均符合,此时t = A[i] + B[i] + 上一位的进位*/
		C.push_back(t % 10);								//当前这一位数,如果 t > 10 , 这一位只能保留个位的值							
		t /= 10;											//求的是有没有向高位进位
	}

	if (t) C.push_back(1);									//如果最高位还有进位,那要在更高位补上 1
	return C;
}

1.2高精度减法(正数)

高精度减法中,大整数的存储方式同高精度加法相同。而计算仍然是模拟人工减法。规则如下:

(1)先看A和B的大小。若A ≥ B , 则直接计算A - B ;若A < B 则要计算的是 -(B - A)。通过这样的变换可以保证每次都是较大的数减去较小的数,最高位不会再往前借位,可以少处理一些边界情况。

(2)A - B 具体每一位的计算:观察 A[ i ] - B[ i ] - t 。其中 A[ i ] 和 B[ i ] 是被减数和减数,t 是低一位的借位,如果低一位借过位,则 t = 1 ,否则 t = 0。

①若 A[ i ] - B[ i ] - t ≥ 0 ,则直接减,计算 A[ i ] - B[ i ] - t

②若 A[ i ] - B[ i ] - t < 0 ,则需要向更高位借位,相当于多了10,即计算A[ i ] - B[ i ] - t + 10

P.S.为何只考虑两个大数都是正数的情况,因为若两个数中存在负数,计算过程是可以转变为两个数的绝对值(即正数)相减或相加的问题,依然可以套模板,因此若包含负数也不是模板的问题,而是输入输出的问题。

C++代码模板

// C = A - B, 满足A >= B, A >= 0, B >= 0
vector<int> sub(vector<int> &A, vector<int> &B)
{    
    int t = 0;                    //t 表示借位 , 初始为 0 ,根据手算规则从个位依次往高位进行减法 , 因此初始时 i = 0
    vector<int> C;                
    for (int i = 0; i < A.size(); i ++ )
    {//t 是当前这位的值 ,到这里是被减数这一位 - 上一位从这一位借位
     //先判断 B 有没有这一位
        t = A[i] - t;            
        if (i < B.size())        
     //如果 B 也有这一位才需要减 , 那么此时当前这位计算的值是被减数的这一位 - 上一位的借位 - 减数当前这位: A[i] - B[i] - t;
            t -= B[i];            
     //如果之前的计算 t 的值是 ≥0 的,那么 (t + 10) % 10 == t ;
     //如果之前计算的 t 是一个负数,则说明被减数这一位不够减,需要向更高位借位,(t + 10) % 10 == t + 10 , 即相当于借了一位 
        C.push_back((t + 10) % 10);    
     //如果之前计算的 t 是一个负数,则说明有借位 , 把t的值变为 t = 1 , 作为下一位的计算条件;
        if (t < 0) t = 1;              
        else t = 0;                    //否则 t = 0,表示没有向更高一位借位
    }
//减法的一个问题是 A 有多少位 C 就会有多少位 , 如果算出来 C 的实际位数比 A 少 , 前面不足的位会用 0 填充 , 因此要去掉前导的 0
    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}

1.3高精度乘低精度

高精度乘法中,一般一个数是大整数,而另外一个数是低精度(一般不超过10000)。计算方法与手算乘法略有不同。简言之,手算两个多位整数,是依次用乘数的各个数位上的数,分别去乘被乘数的每一位,然后将乘得的积加起来得到结果的每一位。而在高精度乘低精度中,是依次用乘数分别去乘被乘数的每一位,然后提取出结果的一位和进位。具体如下:

C++代码模板

//C = A * b, A >= 0 , b >= 0, b 是低精度的,要在10000以内
vector<int> mul(vector<int> &A , int b){
	int t = 0;
	vector<int> C;
	//如果 i 已经处理到最后一位数了,但是 t 还有数字的话,没有 ||t就会忽略这些存留的 t,
	//如果有 ||t 的话就会继续把 t 丢到下面的for循环中,直到 t 被处理输出到 0位置。
    //也可以为 t 单独列一个循环,循环内容相同
	for(int i = 0; i < A.size() || t; i ++){
		if( i < A.size())	t += A[i]*b;
		C.push_back(t % 10);
		t /= 10;
	}
	
	while(C.size() > 1 && C.back() == 0)
		C.pop_back();
	return C;
}

 1.4高精度除以低精度

(1)每次判断当前余数 r,初始时余数为被除数 A 的最高位,余数 r 除以除数 b 向下取整得到一位商 C[ i ],不够除则商0(包括商的最高位不够除也同样上商0),除完后余数和除数做模运算  (r mod b),得到新的余数 r'。

(2)r' × 10 + A[ i - 1 ]。在手算中我们直接把被除数的低移动下来,和上一轮运算的余数组合后成为新一轮运算的被除数,在计算机内实质相当于 r' × 10 后加上被除数下一位的值。继续除以 b 并向下取整得到下一位商 C[ i - 1 ],r‘ 和 b 做模运算(r mod b),得到新的余数 r''。( r'' = r' × 10 + A[ i - 1 ] - C[ i - 1 ] × b,实际上就相当于上一次运算的余数 r' 和 除数 b 做取余运算)。

如图所示:

 C++代码模板

// A / b = C ... r, A >= 0, b > 0
vector<int> div(vector<int> &A, int b, int &r)			
{    //除了被除数A,除数b以外还有一个余数r
    vector<int> C;								//定义商
    r = 0;									//余数初始为0
    //与+-×的模板不同,这里是从高位开始算
    for (int i = A.size() - 1; i >= 0; i -- )					
    {   //平时我们手算时是直接把数字拉下来就计算了,但公式上等价于:余数×10+A[i]
        r = r * 10 + A[i];					
        C.push_back(r / b);
        r %= b;
    }
    //注意之前的计算,C[0]存的是最高位,C[n]存的是最低位,与前面定义的大整数除法是逆过来的,因此此处需要reverse()函数调整顺序
    reverse(C.begin(), C.end());
    //除法同样存在前导0的问题,因此要去掉前导0		
    while (C.size() > 1 && C.back() == 0) C.pop_back();	
    return C;
}

/*除法是从高位开始算,所以理论上如果题目里只有除法的话正着存会比较好
   但一般情况下题目是加减乘除混合的,为了统一起来,除法存储也只能是倒着存*/

2.前缀和

前缀和和差分互为逆运算。 

2.1一维前缀和

2.1.1概念

前缀和即为数组的前 i 项的和。

原数组:a[1] , a[2] , a[3] , ... , a[n]

前缀和:S[i] = a[1] + a[2] + a[3] + ... + a[i] (i ≠ 0) ,特别要注意的是S[0] = 0

S[0] = 0

S[1] = a[1]

S[2] = a[1] + a[2]

2.1.2如何求S[i]:

for(int i = 1; i <= n; i ++)
    S[i] = S[i - 1] + a[i];

2.1.3作用

 快速求原数组中某一段元素【l , r】的和。

图解: 

注意:
S[0]定义为0的好处是方便处理边界

例:a[1] ~ a[10]所有元素的和,实际上就是S[10]。为了统一求数组某一段之和的公式,将S[0]定义为0,就可以用同一个公式处理所有情况,免去了边界条件的判断。

数组下标一定要从1开始,从1开始是为了能定义S[0],下标从1开始则S[0]无需对应任何变量,可定义为0。

C++代码模板

1.预处理:时间复杂度 T1 = O(n)

	for(int i = 1; i <= n; i ++)			//定义原数组
		scanf("%d" , &a[i]);
	for(int i = 1; i <= n; i ++)			//求前缀和数组
		S[i] = S[i - 1] + a[i];

2.求解:时间复杂度 T2 = O(1)

int l , r;
cin >> l >> r;
cout << S[r] - S[l - 1];

2.2二维前缀和

2.2.1概念

将求一维前缀和的概念拓展到二维,很容易理解二维前缀和是什么一回事。二维前缀和即二维数组下标小于等于【i,j】的所有元素的和。如图蓝色区域所示:

 计算原理

要计算S[ i ][ j ],首先求出绿色方框的区域的二维前缀和,再求出红色方框的区域的二维前缀和,两种颜色方框重叠的部分多算了一次前缀和,因此需要再减去重叠部分的二维前缀和,则可得到上图蓝色区域内的S[ i ][ j ]。

 \large S_{i,j} = S_{i,j-1} + S_{i-1,j} - S_{i-1,j-1} + a_{i,j}

如图所示:

 注意:数组下标仍然是从1开始!

2.2.2如何求S[i][j]

C++代码模板 

int a[N][N] , S[N][N];    // N由实际需要确定其值

for(int i = 1; i <= n; i ++)                        //先定义数组元素
    for(int j = 1; j <= m; j ++){
        scanf("%d" , &a[i][j]);
    }
for(int i = 1; i <= n; i ++)                        //求前缀和
    for(int j = 1; j <= m; j ++){
        S[i][j] = S[i - 1][j] + S[i][j - 1] - S[i - 1][j - 1] + a[i][j];
    }

 2.2.3作用

求某个子矩阵内所有元素之和。

计算原理

要计算(x1 , x2)和(y1 , y2)所围成的子矩阵(二维数组)内所有元素之和,需要利用二维前缀和。为了得出图中蓝色部分子矩阵之和,可以利用大矩阵前缀和S[ x2 ][ y2 ]分别减去两块无关的小矩阵的前缀和,而两块小矩阵重叠的部分多减了一次,因此再补回重叠部分的小矩阵的元素和即可求出子矩阵的和。

\large S_{x_{2},y_{2}} - S_{x_{2},y_{1}-1} - S_{x_{1}-1,y_{2}} + S_{x_{1}-1,y_{1}-1}

 如图所示:

 C++代码模板

int S[N][N];    // N由实际需要确定其值
int x1 , x2 , y1 , y2;
scanf("%d%d%d%d",&x1 , &y1 , &x2 , &y2);
//计算子矩阵的和
printf("%d\n" , S[x2][y2] - S[x2][y1-1] - S[x1 - 1][y2] + S[x1-1][y1-1]);

3.差分

差分是前缀和的逆运算

3.1一维差分

3.1.1概念

原数组:a[1] , a[2] , a[3] , ... , a[n]

然后构造出一个数组:b[1] , b[2] , b[3] , ... , b[n]

使得 a[i] = b[1] + b[2] + ... + b[i] (1 ≤ i ≤ n ).

即,a[ i ] 数组是 b[ i ] 数组的前缀和数组,b[ i ] 数组是 a[ i ] 数组的差分数组。

3.1.2构造一维差分数组

在已知 a[ i ] 数组的情况下,构造 b[ i ] 数组方式如下:

b[1] = a[1]

b[2] = a[2] - a[1]

b[3] = a[3] - a[2]

......

b[n] = a[n] - a[n - 1]

3.1.3作用

有一种情况,要求数组 a[n] 中间某一段连续区间内的所有元素,例如a[l]到a[r]的所有元素,每一个都加上一个固定值。有两种处理方式:

(1)直接处理:将数组a[n]的【l , r】内元素循环一遍,每个加上c,这样时间复杂度T = O(n)

(2)差分:

        ①对b[n]数组进行操作,令 b[ l ] + c ,则 b[1] + b[2] + ... + (b[l] + c) = a[l] + c ,只要b[ l ]加上c ,则 a[ l ] 及之后所有元素都会加上 c ;

        ②为了让【l , r】内元素 +c ,只需在上一步的基础上,令 b[r + 1] - c 即可,即对于任意的   i > r ,有b[1] + b[2] + ... + (b[l] + c) + b[l + 1] + ... + b[r] + (b[r + 1] - c) + ... + b[i] = a[i]

 为此可以看图方便理解:

 综上,只需要对差分数组 b[ i ] 做 b[ l ] + c 和 b[ r + 1 ] - c 。因此时间复杂度T = O(1)

C++代码模板(y总)



const int N = 100010;

int a[N] , b[N];				//a[N],b[N]初始化为0

int n;                          //原数组元素个数

void insert(int l , int r , int c){			//为实现序列[l , r]内所有元素全部加上c
	b[l] += c;
	b[r + 1] -= c;
}

main(){

	for(int i = 1; i <= n; i ++)			//定义数组a[n]
		scanf("%d",&a[i]);
	
	for(int i = 1; i <= n; i ++)		//构造差分数组b[n],手动写出来看一下就知道了
		insert(i, i, a[i]);
									
	int l , r , c;                          //l , r为区间左右端点,c为要加上的数
	
	insert(l , r , c);					    //b[l] + c , b[r + 1] - c

	
	for(int i = 1; i <= n; i ++)	
		b[i] += b[i - 1];					//数组b[n]求前缀和,实现原数组[l , r]内元素+c
	
	for(int i = 1; i <= n; i ++)			//输出结果
		printf("%d " , b[i]);
	
}

以上是y总的模板,对于 insert(i , i , a[i]) 是构造查分数组可能不太容易理解,由insert()函数定义画个图便可理解这行代码做了什么: 

即3.1.2.中提到的“构造差分”,因此通过上述过程我们即可得到差分数组 b[ i ]。它的思路是这样的:刚开始时默认 a[ i ] 和 b[ i ] 数组全0,假定 b[ i ] 数组是 a[ i ] 数组的差分数组,但实际上 a[ i ] 数组是有定义的(我们输入 a[ i ] 的各个元素就是给 a[ i ] 数组以定义),因此为了维持 b[ i ] 数组仍是 a[ i ] 数组的差分数组,那么要让 b[ i ] 对应位置也加上 a[ i ]。

还有一个从逻辑上更便于理解的模板,该模板直白地体现了构造差分数组、b[ l ] + c 和 b[ r + 1 ] + c、差分数组求前缀和实现[l , r]内所有元素加上固定值的逻辑过程:

C++代码模板

const int N = 1e5 + 10;

int a[N], b[N];

main()
{
    int n;
    scanf("%d", &n);

    //构建差分数组
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        b[i] = a[i] - a[i - 1];      
    }

    //将序列中[l, r]之间的每个数都加上c
    int l, r, c;                     
    scanf("%d%d%d", &l, &r, &c);
    b[l] += c;                       
    b[r + 1] -= c;
    
    //数组b[n]求前缀和,实现原数组[l , r]内元素+c
    for (int i = 1; i <= n; i++)
    {
        a[i] = b[i] + a[i - 1];    
        printf("%d ", a[i]);
    }
}

3.2二维差分

3.2.1概念

有了一维差分的概念,可以将差分扩展到二维。

假设原矩阵:a[ i ][ j ](其中 1 ≤ i ≤ n,1 ≤ j ≤ n),

要构造一个差分矩阵:b[ i ][ j ],使得a数组的元素 a[ i ][ j ] 是 b 数组左上角(1 , 1)到右下角(i , j)所包围的矩形内所有元素的和。

3.2.2构造二维差分数组

设想出一个差分数组b[ i ][ j ],其必须满足一个性质:a[ i ][ j ]是b数组的前缀和。其思路同一维是一样的,只不过公式不同而已。它的思路是这样的:刚开始时默认 a[ i ][ j ] 和 b[ i ][ j ] 数组全0,假定 b[ i ][ j ] 数组是 a[ i ][ j ] 数组的差分数组,但实际上 a[ i ][ j ] 数组是有定义的(我们输入 a[ i ][ j ] 的各个元素就是给 a[ i ][ j ] 数组以定义),因此为了维持 b[ i ][ j ] 数组仍是 a[ i ][ j ] 数组的差分数组,那么要让 b[ i ][ j ] 对应位置也加上 a[ i ][ j ]。第一次在 (1 , 1)到(1 , 1)的范围内插入了一个a[ 1 ][ 1 ](其实就是在一个小方格内的元素),第二次在(1 , 2)到(1 , 2)的范围内插入了一个a[ 1 ][ 2 ]......以此类推。n*m 次插入操作后,a[ i ][ j ]数组就是b[ i ][ j ]数组的前缀和数组,b[ i ][ j ]数组就是a[ i ][ j ]数组的差分数组。

3.2.3作用

类比于一维差分的作用,二维差分的作用是给矩阵(二维数组)的某个子矩阵加上一个固定值 c 。设需要给左上角坐标(x1 , y1),右下角坐标(x2 , y2)的子矩阵所有元素+c:

(1)若采用枚举遍历整个子矩阵所有元素的方法,需要时间复杂度T = O(n*m)

(2)差分:

        ①令 b[ x1 ][ y1 ] += c ,则该元素及右下角所有元素(即下标 i ≥ x1 ,j ≥ y1 的所有元素)均 +c(图中橙色方框部分);

        ②令 b[ x2 + 1 ][ y1 ] -= c,则该元素及右下角所有元素均 -c,与①中的 +c 抵消(图中红色方框部分);

        ③令 b[ x1 ][ y2 + 1 ] -= c,则该元素及右下角所有元素均 -c,与①中的 +c 抵消(图中绿色方框部分);

        ④红色和绿色矩形框重叠部分即②③步中重复计算的部分,因此重叠部分需 +c 补回,即      b[ x2 + 1 ][ y2 + 1 ] += c。

 由于只需处理4个数,因此时间复杂度T = O(1)

 C++代码模板

int a[N][N] , b[N][N];

//为实现子矩阵内所有元素都加上c
void insert(int x1 , int y1 , int x2 , int y2 , int c){				
	b[x1][y1] += c;
	b[x2 + 1][y1] -= c;
	b[x1][y2 + 1] -= c;
	b[x2 + 1][y2 + 1] += c;
}

main(){
	int n , m , q;
	cin >> n >> m >> q;
	for(int i = 1; i <= n; i ++)
		for(int j = 1; j <= m; j ++)
			cin >> a[i][j];
			
	//构建差分数组
	for(int i = 1; i <= n; i ++)					
		for(int j = 1; j <= m; j ++)
			insert(i , j , i , j , a[i][j]);
			
	//q次插入不同的c
	while(q --){
		int x1 , y1 , x2 , y2 , c;
		cin >> x1 >> y1 >> x2 >> y2 >> c;
		insert(x1 , y1 , x2 , y2 , c);        
	}
	
	//二维前缀和
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= m; j ++){
			a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + b[i][j];
			cout << a[i][j] << " ";
		}
		cout << endl;
	}
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
前缀和差分是一类常用的算法,它们常常被用来优化一些区间操作的问题,如求区间和、区间最大值/最小值等等。下面我们将分别介绍前缀和差分的定义、用法和常见问题。 ## 前缀和 前缀和,顾名思义,就是把前面所有数的和都求出来,用一个数组存起来,以便之后的查询。 ### 定义 给定一个长度为 $n$ 的序列 $a$,令 $s_i = \sum_{j=1}^{i}a_j$,则 $s$ 称为序列 $a$ 的前缀和数组。 ### 用法 前缀和的主要作用是用 $O(1)$ 的时间复杂度求出一个区间 $[l,r]$ 的和,即 $s_r - s_{l-1}$。这是因为 $s_r$ 存储了序列从 $1$ 到 $r$ 的和,而 $s_{l-1}$ 存储了序列从 $1$ 到 $l-1$ 的和,因此区间 $[l,r]$ 的和可以通过两个前缀和相减计算得出。 前缀和的时间复杂度为 $O(n)$,因为需要遍历一遍序列求出前缀和数组。但是,如果有多个查询需要求区间和,那么使用前缀和可以将每次查询的时间复杂度降低到 $O(1)$。 ### 代码实现 下面是使用前缀和求区间和的代码实现: ```cpp vector<int> a; // 原序列 vector<int> s(a.size() + 1); // 前缀和数组 // 计算前缀和 for (int i = 1; i <= a.size(); i++) { s[i] = s[i - 1] + a[i - 1]; } // 查询区间 [l, r] 的和 int sum = s[r] - s[l - 1]; ``` ## 差分 差分前缀和相反,它主要用来对区间进行修改。我们可以利用差分数组进行区间修改,并最终得到修改后的序列。 ### 定义 给定一个长度为 $n$ 的序列 $a$,令 $d_i = a_i - a_{i-1}$($d_1 = a_1$),则 $d$ 称为序列 $a$ 的差分数组。 ### 用法 差分的主要作用是对区间进行修改。假设我们需要将区间 $[l,r]$ 的数加上 $k$,我们可以将差分数组的 $d_l$ 加上 $k$,将 $d_{r+1}$ 减去 $k$。这样,对差分数组求前缀和,就可以得到修改后的序列。 具体来说,我们可以按照以下步骤进行区间修改: 1. 对差分数组的 $d_l$ 加上 $k$; 2. 对差分数组的 $d_{r+1}$ 减去 $k$; 3. 对差分数组求前缀和,得到修改后的序列。 差分的时间复杂度为 $O(n)$,因为需要遍历一遍序列求出差分数组。但是,如果有多次区间修改需要进行,那么使用差分可以将每次修改的时间复杂度降低到 $O(1)$。 ### 代码实现 下面是使用差分进行区间修改的代码实现: ```cpp vector<int> a; // 原序列 vector<int> d(a.size() + 1); // 差分数组 // 计算差分数组 for (int i = 1; i < a.size(); i++) { d[i] = a[i] - a[i - 1]; } // 修改区间 [l, r],将数加上 k d[l] += k; d[r + 1] -= k; // 对差分数组求前缀和,得到修改后的序列 for (int i = 1; i < d.size(); i++) { a[i] = a[i - 1] + d[i]; } ``` ## 常见问题 ### 1. 差分数组的长度是多少? 差分数组的长度应该比原序列长度多 1,因为 $d_1 = a_1$。 ### 2. 什么情况下使用前缀和?什么情况下使用差分? 如果需要进行多次区间查询,那么使用前缀和可以将每次查询的时间复杂度降低到 $O(1)$;如果需要进行多次区间修改,那么使用差分可以将每次修改的时间复杂度降低到 $O(1)$。 ### 3. 前缀和差分的本质区别是什么? 前缀和差分都是用来优化区间操作的算法,它们的本质区别在于: - 前缀和是通过预处理前缀和数组来优化区间查询; - 差分是通过预处理差分数组来优化区间修改。 ### 4. 前缀和差分能否同时使用? 当然可以。如果需要同时进行区间查询和修改,我们可以先使用差分数组对区间进行修改,然后再对差分数组求前缀和,得到修改后的序列。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值