周周小训练2

路径计数

有一个𝑛×𝑛的网格,有些格子是可以通行的,有些格子是障碍。

一开始你在左上角的位置,你可以每一步往下或者往右走,问有多少种走到右下角的方案。

由于答案很大,输出对109+7取模的结果。

输入格式

第一行一个正整数𝑛

接下来𝑛行,每行𝑛个正整数,1表示可以通行,0表示不能通行。

输出格式

一个整数,表示答案。

样例输入

3
1 1 1
1 0 1
1 1 1

样例输出

2

数据规模

对于100%的数据,保证2≤𝑛≤100,左上角右下角都是可以通行的。

解题思路:

dp

对于每一个通路格1能走到的方法总数,

等于它上面一个通路格能走到的方法总数+左边一个通路格能走到的方法总数

dp [i] [j] =dp [i-1] [j] +dp [i] [j-1]

完整代码如下:

#include <bits/stdc++.h>
using namespace std;
​
const int maxn=1e2+5,mod=1e9+7;
​
int n;
int tu[maxn][maxn],dp[maxn][maxn];
​
int main()
{
    cin>>n;
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++){
            cin>>tu[i][j];
        }
    }
    dp[1][1]=1;//初始化为1 
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++){
            if(i==1 && j==1) continue; //跳过起点 
            if(tu[i][j]==1) dp[i][j]=(dp[i-1][j]+dp[i][j-1]) % mod;
        }
    }
    cout<<dp[n][n];
    return 0;
}

最大和上升子序列

给定一个长度为 𝑛 的数组 𝑎1,𝑎2,…,𝑎**𝑛,问其中的和最大的上升子序列。也就是说,我们要找到数组 𝑝1,𝑝2,…,𝑝**𝑚,满足 1≤𝑝1<𝑝2<⋯<𝑝**𝑚𝑛 并且 𝑎**𝑝1<𝑎**𝑝2<⋯<𝑎𝑝𝑚,使得𝑎**𝑝1+𝑎**𝑝2+⋯+𝑎𝑝𝑚最大。

输入格式

第一行一个数字 𝑛

接下来一行 𝑛 个整数 𝑎1,𝑎2,…,𝑎**𝑛

输出格式

一个数,表示答案。

样例输入

6
3 7 4 2 6 8

样例输出

21

数据规模

所有数据保证 1≤𝑛≤1000,1≤𝑎**𝑖≤10^5。

解题思路:

dp

对于每一个数可以选择它之前满足序列的最大序列与其相加

eg. 3 7 4 2 6 8

3 10 7 2 13 21

最后找出其中的最大序列

完整代码如下:

#include <bits/stdc++.h>
using namespace std;
​
const int maxn=1e5+5;
int a[maxn],dp[maxn];
int n;
​
int main()
{
    cin>>n;
    for(int i=1; i<=n; i++) cin>>a[i];
    for(int i=1; i<=n; i++) dp[i]=a[i];
    for(int i=1; i<=n; i++){
        for(int j=1; j<=i; j++){
            if(a[i]>a[j]) dp[i]=max(dp[i],a[i]+dp[j]);
        }
    }
    int max=0;
    for(int i=1; i<=n; i++){
        if(dp[i]>max) max=dp[i];
    }
    cout<<max;
    return 0;
}

加一

给定一个整数 𝑛。你需要对它做 𝑚 次操作。在一次操作中,你要将这个数的每一位 𝑑 替换成 𝑑+1。比如,1912在进行一次操作后将变成 21023。

请求出整数 𝑛 进行了 𝑚 次操作后的长度。答案可能很大,输出对 10^9+7 取模后的结果。

输入格式

第一行一个整数 𝑡,表示测试单元的个数。

接下来 𝑡 行,每行有两个整数 𝑛𝑚,表示最初的数字和进行多少次操作。

输出格式

对于每个测试单元输出最终数字的长度,答案对 10^9+7 取模。

样例输入

5
1912 1
5 6
999 1
88 2
12 100

样例输出

5
2
6
4
2115

数据规模

所有数据保证 1≤𝑡≤2⋅10^5,1≤𝑛≤10^9,1≤𝑚≤2⋅10^5。

解题思路:

其中的每一个数字都是独立的,所以只要对每一个数字进行m次操作后形成的数字长度进行累加就行

因为数字是独立的,所以可以对所有数字进行预处理,最后累加时直接调用即可,减少时间复杂度

完整代码如下:

#include <bits/stdc++.h>
using namespace std;

const int maxn=2e5+5,M=2e5+5,mod=1e9+7;

int t,n,m;

long long a[10],b[10],dp[10][maxn];

int main()
{
	//先模拟进行预处理 
	for(int i=0; i<=9; i++){
		a[i]=1;//将每个数都从数量1开始 
		for(int j=1; j<=M; j++){ 
			b[0]=a[9];
			b[1]=(a[0]+a[9])%mod;
			for(int k=2; k<=9; k++){
				b[k]=a[k-1];
			}//一次循环所有数字的数量变化 
		for(int k=0; k<=9; k++){
		    dp[i][j]=(dp[i][j]+b[k])%mod;
	        }//用dp存什么数操作几次后有几个 
	    for(int k=0; k<=9; k++){
			a[k]=b[k];
		    }//将b数组中的数拷贝到a数组中 
		}
		memset(a,0,sizeof(a));//每一次模拟结束要对a数组清空 
	}
	scanf("%d",&t);
	while(t--){
	    scanf("%d%d",&n,&m);
        long long sum=0;
	    while(n>0){
	    	sum=(dp[n%10][m]+sum)%mod;
	    	n/=10;
		}//对每一个数字进行处理 
	printf("%d\n",sum);
	}
	return 0;
} 

跳跳

平面上给定了一些整点(横纵坐标均为整数的点),被称为 “魔法阵”。魔法少女派派想要在各魔法阵之间传送,每一次传送,她将使用下面的方式:

  1. 刚开始,派派已经位于某传送阵之上;

  2. 如果派派掌握一种魔法 (𝐴,𝐵),其中 𝐴,𝐵均为整数。使用一次这个魔法可以让派派从任意整点 (𝑋,𝑌) 瞬间移动至 (𝑋+𝐴,𝑌+𝐵);

  3. 选择一种魔法并开始传送,在一次传送过程中可以使用多次该魔法,但在抵达下一个传送阵之前仅能使用这一种魔法

问派派至少需要掌握多少种魔法,才能在从任意魔法阵直接传送到任意魔法阵?

输入格式

第一行一个整数 𝑁

接下来一行 𝑁 行,每行包含两个整数 𝑋**𝑖,𝑌**𝑖, 表示每个魔法阵的坐标。

输出格式

一个数,表示答案。

样例1输入

3
1 1
4 5
1 4

样例1输出

6

解释: 任务是从 (1,1) 传送至 (4,5) 以及 (1,4) 、从 (4,5) 传送至 (1,1) 以及 (1,4) 、从 (1,4) 传送至 (1,1) 以及 (4,5) 。

注意你不能使用 (0,3)+(3,1) 的魔法从 (1,1) 到达 (4,5)。因为每次移动,你只能使用一种魔法。

当然,你可以学习 (0,1),那样的话,从 (1,1)到达 (1,4) 则需要使用 3次 (0,1) 魔法了。

样例2输入

3
1 1
2 2
1000000000 1000000000

样例2输出

2

数据规模

  • 𝑁∈[10,500]

  • 𝑋**𝑖,𝑌**𝑖∈[0,109], 但保证坐标之间两两不同

解题思路:

假设从坐标1传送到坐标2,再从坐标2传送到坐标1,魔法的绝对值数值是相同的,所以只需要考虑正的,最后将次数乘以2即可

从坐标1开始,依次对后面的坐标选取魔法,

每次选取一种魔法,要取魔法的最大公约数,然后把魔法最简化,最后用最简化的魔法去寻找能够达到的坐标

直到坐标全能到达为止

最后将选取的魔法数乘以2就是总魔法数

完整代码如下:

#include <bits/stdc++.h>
using namespace std;

const int maxn=505;

int n,q,w,cnt=0,s;

struct ch{
	int x;
	int y;
}p[maxn];

int chuan[maxn][maxn]={0};//记录此坐标是否有魔法已经可以传送到 

int gcd(int x,int y);

int main()
{
	cin>>n;
	for(int i=1; i<=n; i++) cin>>p[i].x>>p[i].y;
	for(int i=1; i<=n; i++){
		for(int j=i+1; j<=n; j++){
			if(chuan[i][j]==0){
			cnt+=2;	
			chuan[i][j]=1;
			q=p[j].x-p[i].x;
			w=p[j].y-p[i].y;
			s=gcd(q,w);//寻找最大公约数 
			q/=s;
			w/=s;
			//最简化魔法 
			for(int k=j+1; k<=n; k++){
				if((p[k].x-p[i].x)%q==0 && (p[k].y-p[i].y)%w==0) chuan[i][k]=1;
				if((p[k].x-p[j].x)%q==0 && (p[k].y-p[j].y)%w==0) chuan[j][k]=1;
			    }//寻找能够达到的魔法阵 
		    }
		}
	}
	cout<<cnt;
	return 0;
}

int gcd(int x,int y)
{
	if(x<y) swap(x,y);
	int m;
	while(y){
	m=x%y;
	x=y;
	y=m;
    }
	return x;
}

异或和或

对于一个长度为 𝑛 的01序列 𝑎1,𝑎2,…,𝑎**𝑛

你可以执行以下操作任意多次:

  • 选择两个下标 1≤𝑖,𝑗𝑛(𝑖𝑗)。

  • 𝑥=𝑎**𝑖 xor 𝑎**𝑗 , 𝑦=𝑎**𝑖 or 𝑎**𝑗 , 其中 xor 表示按位异或 , or 表示按位或。

  • 然后令 𝑎**𝑖=𝑥,𝑎**𝑗=𝑦𝑎**𝑖=𝑦,𝑎**𝑗=𝑥

给定两个01序列 𝑠,𝑡 , 请你判断是否可以通过有限次(可以为0次)操作将序列 𝑠 变为 𝑡

输入格式

第一行一个整数 𝑡 , 表示数据的组数(1≤𝑡≤10^3)。接下来 𝑡组数据:

每组第一行一个01字符串 𝑠(1≤|𝑠|≤10^3),每组第二行一个01字符串 𝑡(1≤|𝑡|≤10^3)。

注意:|𝑠| 可能不等于 |𝑡|。

输出格式

如果可以通过有限次(可以为0次)操作将序列 𝑠 变为 𝑡, 输出 YES , 否则输出 NO

样例输入

2
001
011
11
101

样例输出

YES
NO

样例解释

第一组数据选择 𝑖=2,𝑗=3 , 那么 𝑥=1,𝑦=1 , 接着令 𝑎**𝑖=𝑥,𝑎**𝑗=𝑦 即可得到 𝑡 序列。

第二组数据 |𝑠|=2,|𝑡|=3 显然无法满足要求。

解题思路:

1当两个序列长度相同时:

一共可分三种情况: xor or

0 0 0 0

1 0/1 0 1 1

1 1 0

由此发现,只要序列中有1存在,都能转化为全是1的序列m,也就是s->m,t->m,s->t

所以只要序列中有1,或者s,t都全为0,就输出YES

反之都输出NO

2当两个序列长度不同时,直接输出NO

完整代码如下:

#include <bits/stdc++.h>
using namespace std;

int main()
{
	int t;
	cin>>t;
	string a,b;
	while(t--){
		cin>>a>>b;
		int sa,sb;
		sa=a.length();
		sb=b.length();
		if(sa!=sb){
			cout<<"NO"<<endl;
			continue; //不能写return 0,有多组数据 
		}
		int cnt1=0,cnt2=0;
		for(int i=0; i<sa; i++){
			if(a[i]=='1') cnt1++;
		}
		for(int i=0; i<sb; i++){
			if(b[i]=='1') cnt2++;
		}
		if(cnt1>0 && cnt2>0) cout<<"YES"<<endl;
		else if(cnt1==0 && cnt2==0) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	return 0;
}

01序列

我们称一个字符串为好字符串,指这个字符串中只包含01

现在有一个好字符串,求这个字符串中1恰好出现𝑘次的子串有多少个。

输入格式

第一行给出一个数字𝑘,表示子串中1的个数。

第二行给出好字符串。

输出格式

输出一个整数,表示好字符串中有多少个符合条件的子串

数据范围

0≤𝑘≤10^6, |𝑠|≤10^6

样例输入1

1
1010

样例输出1

6

样例输入2

2
01010

样例输出2

4

解题思路:

题目要求我们找的是子串中1的个数为k的情况有多少,我们当然可以枚举字串的长度,然后遍历字串的组成情况,如果满足要求则计数器++,但这样的时间复杂度为O(n^2),在这题1e6的数据下显然是会超时的,所以我们想办法把题目转化一下。

既然是子串,那就说明是连续的,且字符串除了0就是1,那么我们可以用前缀和的思路来写,这样问题就变成了,区间和为k的情况有多少。

我们计算子串的前缀和数组,并把相同前缀和的数量用哈希表记录下来。每一个前缀和为sum的位置,都能和所有前缀和为sum-k的位置形成好子串,所以我们计数器记录的是(前缀和为sum的数量 * 前缀和为sum-k的数量)。最后只要把计数器输出即可。

但有一种情况是特殊的,即k=0的情况,如果k=0,那么我们记录的子串数量就是(前缀和为sum的情况 * 前缀和为sum的情况),这显然是不对的,会出现重复的好子串。所以遇到k=0时我们应该特殊处理,它的子串数为:连续ans个0组成的子串,它能形成的不同好子串为:(ans+1) * ans/2。

完整代码如下:

#include <bits/stdc++.h>
using namespace std;

const int maxn=1e6+5;

int f[maxn],cnt[maxn];

int main()
{
	long long k,t=0,sum=0,m;
	cin>>k;
	string s;
	cin>>s;
	m=s.length(); 
	if(k==0){
		long long ans=0;
		for(int i=0; i<m; i++){
			if(s[i]=='0') ans++;
			else{
				 sum+=(ans+1)*ans/2; 
				 ans=0;
			}
		}
		if(sum==0) sum+=(ans+1)*ans/2;//防止序列全是0 
	}else{
	for(int i=0; i<m; i++){
		if(s[i]=='1') f[i]=f[i-1]+1;
		else f[i]=f[i-1];
	}
	cnt[0]=1;//初始化为1,防止漏算从开头开始的子串 
    for(int i=0; i<m; i++){
    	cnt[f[i]]++;
	}
	for(int i=0; i<=m-k; i++){
		sum+=cnt[i]*cnt[i+k];
	    }
    }
	cout<<sum;
	return 0;
}

出栈序列判断

现在有一个栈,有 𝑛 个元素,分别为 1,2,…,𝑛。我们可以通过 pushpop 操作,将这 𝑛 个元素依次放入栈中,然后从栈中弹出,依次把出栈的元素写下来得到的序列就是出栈序列。

比如 𝑛=3,如果执行 push 1, push 2, pop, push 3, pop, pop,那么我们 pop 操作得到的元素依次是 2,3,1。也就是说出栈序列就是 2,3,1。

现在给定一个合法的出栈序列,请输出一个合法的由 pushpop 操作构成的操作序列。这里要求 push 操作一定是按 1,2,…,𝑛 的顺序。

输入格式

第一行一个整数 𝑛。接下来一行 𝑛 个整数,表示出栈序列。

输出格式

输出 2𝑛 行,每行一个 pushpop 操作,可以证明一个出栈序列对应的操作序列是唯一的。

样例输入1

3
2 3 1

样例输出1

push 1
push 2
pop
push 3
pop
pop

样例输入2

5
1 3 5 4 2

样例输出2

push 1
pop
push 2
push 3
pop
push 4
push 5
pop
pop
pop

数据规模

对于 100% 的数据,保证 1≤𝑛≤100000,输入一定是个合法的出栈序列。

解题思路:

建立一个栈,然后分情况判断:1如果栈为空,则加入一个数

2如果栈顶数与出栈序列的待出栈数相同,则出栈

3如果栈顶数与出栈序列的待出栈数不同,则加入一个数

注意:要用scanf和printf,防止TEL(qwq

完整代码如下:

#include <bits/stdc++.h>
using namespace std;

const int maxn=1e5+5;

stack <int> s;

int a[maxn];

int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1; i<=n; i++) scanf("%d",&a[i]);
	int t=1,m=1;
	for(int i=1; i<=2*n; i++){
		if(s.empty()){
			s.push(m);
			printf("push %d\n",m);
			m++;
			continue;
		}
		if(s.top()==a[t]){
			printf("pop\n");
			t++;
			s.pop();
		}else{
			s.push(m);
			printf("push %d\n",m);
			m++;
		}	
	}
	return 0;
}

序列维护

你有一个序列,现在你要支持几种操作:

  • insert x y,在从前往后的第𝑥个元素后面插入𝑦这个数。如果𝑥=0,那么就在开头插入。

  • delete x,删除从前往后的第𝑥个元素。

  • query k,询问从前往后数第𝑘个元素是多少。

输入格式

第一行一个整数𝑚,表示操作个数。

接下来𝑚行,每行一个上面所述的操作。

输出格式

输出若干行,对于每个查询操作,输出答案。

样例输入

10
insert 0 1
insert 1 2
query 1
query 2
insert 0 3
query 1
delete 1
query 1
insert 1 4 
query 2

样例输出

1
2
3
1
4

数据规模

对于100%的数据,保证𝑚≤10^3。

对于insert操作,保证1≤𝑦≤10^9。

对于所有操作,保证位置不会超出当前序列的长度。

解题思路:

用数组存数字即可,插入时,插入位置后的数字都向后移一位,再将数字插入这个位置

删除时,将删除位置后的数字都向前移一位,覆盖掉删除位置的数字

完整代码如下:

#include <bits/stdc++.h>
using namespace std;

const int maxn=1e5+5;

int p[maxn],q[maxn];

int main()
{
	int m;
	cin>>m;
	string a;
	int b,c,s=0;
	while(m--){
		cin>>a;
		if(a[0]=='i'){
			cin>>b>>c;
			if(b==0){
				for(int i=s; i>=1; i--) p[i+1]=p[i];
				p[1]=c;
				s++;
			}else{
				for(int i=s; i>=b+1; i--) p[i+1]=p[i];
				p[b+1]=c;
				s++;
			}
		}else if(a[0]=='q'){
			cin>>b;
			cout<<p[b]<<endl;
		}else if(a[0]=='d'){
			cin>>b;
			for(int i=b; i<=s; i++) p[i]=p[i+1];
			s--;
		}
	}
	return 0;
}

网格判断

您将获得一个 𝑛×𝑛的网格,网格中每个正方形的颜色为黑色或白色。如果满足以下所有条件,则网格是正确的:

  • 每行的黑色方块数与白色方块数相同。

  • 每列的黑色正方形数与白色方块数相同。

  • 没有行或列具有 3个及以上相同颜色的连续正方形。

给定网格,确定它是否正确。

输入格式

第一行一个数字 𝑛(2≤𝑛≤24), 并且数字 𝑛 是偶数。

接下来 𝑛 行,每行包含一个长度为𝑛的由字符BW组成的字符串,代表网格正方形的颜色。

输出格式

如果网格正确,请打印数字 1 在一行上。否则,请打印数字 0 在一行上。

样例输入

4
WBBW
WBWB
BWWB
BWBW

样例输出

1

解题思路:

直接按照题意写即可,判断条件时仔细点

完整代码如下:

#include <bits/stdc++.h>
using namespace std;

char net[25][25];

int main()
{
	int n;
	cin>>n;
	for(int i=1; i<=n; i++){
		for(int j=1; j<=n; j++){
			cin>>net[i][j];
		}
	}
	int cnt1=0,ans1=0,cnt2=0,ans2=0;//cnt1,cnt2分别记录行,列中白色格子的数目,ans1,ans2分别记录行,列中连续格子的数目 
	bool flag1=true,flag2=true;
	for(int i=1; i<=n; i++){
		for(int j=1; j<=n; j++){
			if(net[i][j]=='W'){
				if(ans1<0) ans1=0;
				cnt1++;
				ans1++;
			}else{
				if(ans1>0) ans1=0;
				ans1--;
			}
			if(ans1==3 || ans1==-3){
				flag1=false;
				break;
			}
		}
		if(!flag1) break;
		if(cnt1!=(n-cnt1)){
			flag1=false;
			break;
		}
		ans1=0;
		cnt1=0;
	}//判断行 
	for(int i=1; i<=n; i++){
		for(int j=1; j<=n; j++){
			if(net[j][i]=='W'){
				if(ans2<0) ans2=0;
				cnt2++;
				ans2++;
			}else{
				if(ans2>0) ans2=0;
				ans2--;
			}
			if(ans2==3 || ans2==-3){
				flag2=false;
				break;
			}
		}
		if(!flag2) break;
		if(cnt2!=(n-cnt2)){
			flag2=false;
			break;
		}
		ans2=0;
		cnt2=0;
	}//判断列 
	if(flag1 && flag2) cout<<1;
	else cout<<0;
	return 0;
}

整齐的数组

Polycarp 有一个长度为 𝑛 的数组 𝑎1,𝑎2,...,𝑎**𝑛𝑛 是偶数)。Polycarp 还得到了一个正整数 𝑘,他开始对数组 𝑎 做如下操作:选择一个下标 𝑖 (1≤𝑖𝑛) 使 𝑎**𝑖 减去 𝑘

在 Polycarp 进行若干次操作后(可能 0 次),数组 𝑎 中的所有数都变成相同的了。请你找到最大的符合要求的 𝑘,如果 𝑘 可以为任意大,请输出 −1。

输入格式

第一行一个整数 𝑡,表示测试单元的个数。

接下来每个测试单元有两行。第一行包含一个偶数 𝑛。第二行包含 n 个整数 𝑎1,𝑎2,...,𝑎**𝑛

输出格式

对于每个测试单元输出单独一行一个整数 𝑘 (𝑘≥1)—— Polycarp 能用来对数组进行操作的最大的数,或者 −1 —— 如果 𝑘 能任意大的话。

样例输入

3
6
1 5 3 1 1 5
8
-1 0 1 -1 0 1 -1 0
4
100 -1000 -1000 -1000

样例输出

2
1
1100

数据规模

所有数据保证 1≤𝑡≤10,4≤𝑛≤40(𝑛 是偶数),−10^6≤𝑎**𝑖≤10^6,并且 n 的总和不超过100。

解题思路:

1如果只有一种数字,那么k可以无限大,直接输出-1

2不止一种数字,那所有数字要变成相同的数字,只能变成最小数

所以可以先将所有数字从小到大排序,然后算出所有数对于最小是的差值,其中的k一定是范围1~最小数之间所

有差值的最大公约数

完整代码如下:

#include <bits/stdc++.h>
using namespace std;

int t,n,ans;

int a[45],b[45];

int check();

int main()
{
	cin>>t;
	while(t--){
		cin>>n;
		for(int i=1; i<=n; i++) cin>>a[i];
		sort(a+1,a+1+n);
		//只有一种数字
		bool flag=true;
		if(a[1]==a[n]) flag=false;
		if(!flag){
			cout<<-1<<endl;
			continue;
		}
		//有两种及以上不同的数字
		ans=0;
		for(int i=2; i<=n; i++){
			if((a[i]-a[1])!=b[ans]) b[++ans]=a[i]-a[1];
		}//存入使所有数能变成最小的那个数的所有可能k 
		int s;
		s=check();//寻找所有数的最大公约数 
		cout<<s<<endl;
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
	}
	return 0;
}

int check()
{
	bool flag=true;
	for(int i=b[1]; i>=1; i--){
		for(int j=1; j<=ans; j++){
			if(b[j]%i!=0){
				flag=false;
				break;
			}
		}
		if(flag) return i;
		else flag=true;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值