数位DP入门题目

数位DP通常是用来求解给你一个 [ l , r ] [l,r] [l,r]区间,求这个区间满足一定条件的数的个数。

个人认为数位DP最重要的两个点:
1、len==0时,即遍历完一个数后,返回什么?
2、dp方程,如何能确保DP的唯一性。

其余的都是套模板

1.Bomb

题目链接:点击此处

题意:求 [ 1 , n ] [1,n] [1,n]中含49的个数

数位DP往往用一个数组来记录 n n n中每一个位的值,这边用 d i g i t [ i ] digit[i] digit[i]表示从个位到最高位的第 i i i位为多少。

比如1234,则 d i g i t [ 1 ] = 4 , d i g i t [ 2 ] = 3 , d i g i t [ 3 ] = 2 , d i g i t [ 4 ] = 1 digit[1]=4,digit[2]=3,digit[3]=2,digit[4]=1 digit[1]=4,digit[2]=3,digit[3]=2,digit[4]=1

在这里,我们要知道,我们如果求到了[1,100]中49的个数,那么[101,200]中49的个数也知道了,同理,往下推,除了一个[401,500]中49的个数不同,其他都是相同的,原因是49可能出现在百位上是4,十位上是9的情况。那么这表示,遇到这种情况我们要特判。

其次,我们对于1234,我们容易通过一些状态得知[1001,1100]中含有49的个数,同理,对于[1101,1200]也是,但是对于[1201,1234]我们不能通过前面那2个得到,因为前面那两组求得的是间隔100的49的数量,但是这里间隔只有34,所以,我们要特殊处理。

从这里,我们也知道,对于上一位为4,这一位为9的情况,我们要特殊判断,对于我们遇到了相应位上有上限的情况(比如对于1234,千位为1,遇到了百位为2时,要开始特判),我们也要判断。

#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<stdio.h>
#include<map>
#include<queue>
using namespace std;
#define Check(x) cout<<"x:"<<x<<" "
#define Min(x,y,z) min(x,min(z,y))
#define Max(x,y,z) max(x,max(z,y))
typedef long long ll;
const int MAXN =2e3 + 5;
const int MAXM = 1e6 + 5;
const ll mod = 1e9 + 7;
int digit[25];
ll dp[25][2];
ll dfs(int len, bool if4, bool limit) {//求得是不满足条件的数目
	if (len == 0)return 1;//例如对于1来讲,不满足条件,肯定就1这一个数,2也是,9也是,因为就一位怎么凑得齐49呢。
	if (!limit && dp[len][if4])return dp[len][if4];//dp表示长度为len中,有无4的不符合条件的个数
	ll cnt = 0, up = (limit ? digit[len] : 9);
	for (int i = 0;i <= up;i++) {
		if (if4 && i == 9)continue;
		cnt += dfs(len - 1, i == 4, limit && i == up);
	}
	if (!limit)dp[len][if4] = cnt;
	return cnt;
}
ll solve(ll num) {
	int k = 0;
	while (num) {
		digit[++k] = num % 10;
		num /= 10;
	}
	return dfs(k, false, true);
}
int main() {
	int t;
	cin >> t;
	while (t--) {
		ll n;
		cin >> n;
		cout << n + 1LL - solve(n) << endl;
	}
}

2.不要62

题目链接:点击此处

题意:给你一个 [ l , r ] [l,r] [l,r]区间,其中不包含4和62的多少。

和上一题有相似之处,对于不包含62,我们只要模仿上一个就行,那么对于4呢?

因为我们在dfs枚举的时候是枚举长度为len的所有情况,如果枚举到4了,那么只要continue就行,就可以把4去掉。

#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<stdio.h>
#include<map>
#include<queue>
using namespace std;
#define Check(x) cout<<"x:"<<x<<" "
#define Min(x,y,z) min(x,min(z,y))
#define Max(x,y,z) max(x,max(z,y))
typedef long long ll;
const int MAXN =2e3 + 5;
const int MAXM = 1e6 + 5;
const ll mod = 1e9 + 7;
int digit[25];
ll dp[25][2];
ll dfs(int len, bool if6, bool limit) {
	if (len == 0)return 1;
	if (!limit && dp[len][if6])return dp[len][if6];
	ll cnt = 0, up = (limit ? digit[len] : 9);
	for (int i = 0;i <= up;i++) {
		if (if6 && i == 2)continue;
		if (i == 4)continue;
		cnt += dfs(len - 1, i == 6, limit && i == up);
	}
	if (!limit)dp[len][if6] = cnt;
	return cnt;
}
ll solve(ll num) {
	int k = 0;
	while (num) {
		digit[++k] = num % 10;
		num /= 10;
	}
	return dfs(k, false, true);
}
int main() {
	ll n, m;
	while (cin >> n >> m) {
		if (n == 0 && m == 0)break;
		cout << solve(m) - solve(n-1) << endl;
	}
}

3.Windy 数

题目链接:点击此处

题目意思:
Windy 定义了一种 Windy 数:不含前导零且相邻两个数字之差至少为 2的正整数被称为 Windy 数。

Windy 想知道,在 [ l , r ] [l,r] [l,r]之间,总共有多少个 Windy 数?

这次我们要得到的数是差大于2的那些数,用st表示上一层的值,这一层老规矩枚举到最大值,如果这一层的值与st的差小于2,continue。

特殊情况就是如果上一层是0,即st==11时,这一层我们选0,那么我们这一层递归的st要是11,而不能是i,因为这表示下一层的数我们还是可以随便选。

#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<stdio.h>
#include<map>
#include<queue>
using namespace std;
#define Check(x) cout<<"x:"<<x<<" "
#define Min(x,y,z) min(x,min(z,y))
#define Max(x,y,z) max(x,max(z,y))
typedef long long ll;
const int MAXN =2e3 + 5;
const int MAXM = 1e6 + 5;
const ll mod = 1e9 + 7;
int digit[25];
ll dp[25][15];
ll dfs(int len, int st, bool limit) {
	if (len == 0)return 1;
	if (!limit && dp[len][st])return dp[len][st];
	int maxx = limit ? digit[len] : 9;
	ll cnt = 0;
	for (int i = 0;i <= maxx;i++) {
		if (abs(st - i) < 2)continue;
		if (st == 11 && i == 0) {
			cnt += dfs(len - 1, 11, limit && i == maxx);
		}
		else {
			cnt += dfs(len - 1, i, limit && i == maxx);
		}
	}
	if (!limit)dp[len][st] = cnt;
	return cnt;
}
ll solve(ll num) {
	int k = 0;
	while (num) {
		digit[++k] = num % 10;
		num /= 10;
	}
	return dfs(k, 11, true);
}
int main() {
	ll n, m;
	cin >> n >> m;
	//cout << solve(m) << " " << solve(n - 1) << endl;
	cout << solve(m) - solve(n-1) << endl;
	
}

4.数字计数

题目链接:点击此处

题意:找出 [ l , r ] [l,r] [l,r]区间中0到9的个数

因为是要讨论0到9,不妨从头0到0-9一个个讨论分析。

首先数位DP肯定要知道有limit,并且在长度为0时要返回一个数,但是要返回多少,这个不确定,为何?其实数位DP从len递归到0,做的是对一个数的分解,也就是说我们递归到0,其实就是分析清楚了一个数的情况。上面几个题为何返回1,是因为他们是符合要求的一个数,这题为何不返回1,因为这题记录的是0到9的个数,返回的应该是这个数中目标数的个数。例如1124,讨论1的个数的话,就返回2,讨论2的个数的话就返回1,讨论3的个数的话就返回0。

其次 d p [ i ] [ j ] dp[i][j] dp[i][j]表示 i i i位数,其中 l e n len len i i i位中含有 j j j个含有对应位。

#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<stdio.h>
#include<map>
#include<queue>
using namespace std;
#define Check(x) cout<<"x:"<<x<<" "
#define Min(x,y,z) min(x,min(z,y))
#define Max(x,y,z) max(x,max(z,y))
typedef long long ll;
const int MAXN =2e5 + 5;
const int MAXM = 1e6 + 5;
const ll mod = 1e9 + 7;
int arr[MAXN];
int digit[20];
ll dp[20][20];
ll ans[10] = { 0 };

ll dfs(int len, bool lead, bool limit, int tar, ll sum) {
	if (len == 0)return sum;
	if ( !limit && ~dp[len][sum])return dp[len][sum];
	ll cnt = 0;
	int maxx = limit ? digit[len] : 9;
	for (int i = 0;i <= maxx;i++) {
		cnt += dfs(len - 1, lead || i, limit && i == maxx, tar, sum + ((lead || i) && (tar == i)));
	}
	if (!limit && lead)dp[len][sum] = cnt;
	return cnt;
}
ll solve(ll num,int tar) {
	memset(dp, -1, sizeof dp);
	int k = 0;
	while (num) {
		digit[++k] = num % 10;
		num /= 10;
	}
	return dfs(k, false, true, tar, 0);
	
}
int main() {
	ll n, m;
	cin >> n >> m;
	solve(m, 1);
	solve(n, -1);
	for (int i = 0;i <= 9;i++) {
		cout <<solve(m,i)-solve(n-1,i) << " ";
	}
	cout << endl;
}

5.同类分布

题目链接:点击此处

[ l , r ] [l,r] [l,r],找出区间中的各位数字之和能整除原数的数的个数。

数位DP, d p [ l e n ] [ s u m ] [ s t ] dp[len][sum][st] dp[len][sum][st],其中 l e n len len表示我们剩下未遍历的位数, s u m sum sum表示我们已遍历的数总和, s t st st表示已遍历的数取模 m o d mod mod的结果。这样 d p [ l e n ] [ s u m ] [ s t ] dp[len][sum][st] dp[len][sum][st]表示的结果具有唯一性。即可以使用记忆化搜索。因为假如我们未处于 l i m i t limit limit状态,我们对于已经遍历的得到的 s u m sum sum s t st st,后序不管遍历得到哪一个数字, s u m sum sum s t st st都是一一对应着变化的。所以我们只要这3个值一确定,如果 d p dp dp有记录,那么就可以得到答案。

最后 l e n = 0 len=0 len=0时返回结果1的条件必须是 s u m = m o d 且 s t = 0 sum=mod 且st=0 sum=modst=0


#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<stdio.h>
#include<map>
#include<queue>
using namespace std;
#define Check(x) cout<<"x:"<<x<<" "
#define Min(x,y,z) min(x,min(z,y))
#define Max(x,y,z) max(x,max(z,y))
typedef long long ll;
const int MAXN = 2e5 + 5;
const int MAXM = 1e6 + 5;
ll n, m;
ll dp[20][200][200];
int digit[20];
ll mod = 0;
ll dfs(int len, ll sum, ll st, bool limit) {
    if (len == 0) {
        if (sum == mod)return st==0?1:0;
        else return 0;
    }
    if (!limit&&~dp[len][sum][st])return dp[len][sum][st];
    int res = limit?digit[len] : 9;
    ll ret = 0;
    for (int i = 0;i <= res;i++) {
        ret += dfs(len - 1, sum + i, (10ll * st + i) % mod, i == res && limit);
    }
    if (!limit)dp[len][sum][st] = ret;
    return ret;
}
ll solve(ll num) {
    int k = 0;
    while (num) {
        digit[++k] = num % 10;
        num /= 10;
    }
    ll ans = 0;
    for (ll i = 1;i <= 9 * k;i++){
        mod = i;
        memset(dp, -1, sizeof dp);
       ans += dfs(k, 0, 0, true);
    }
    return ans;
}
int main() {
    cin >> n >> m;
    cout << solve(m) - solve(n-1) << endl;
}

6.萌数

题目链接:点击此处
只有满足“存在长度至少为2的回文子串”的数是萌的——也就是说,101是萌的,因为101本身就是一个回文数;110是萌的,因为包含回文子串11;但是102不是萌的,1201也不是萌的。

现在想知道从l到r的所有整数中有多少个萌数。

由于答案可能很大,所以只需要输出答案对1000000007(10^9+7)的余数。

整数的长度为1到1000。

这题考了一个思维,就是如果存在4位回文,那么必定存在2位回文。比如1001中,00必定是回文。

所以本题只要看遍历的那个数和前面2个数是否组成回文就行。

个人认为数位DP其实难点在于如何确定唯一条件。

本题 d p [ l e n ] [ p r e 1 ] [ p r e 2 ] [ h a v e ] dp[len][pre1][pre2][have] dp[len][pre1][pre2][have],首先 l e n len len表示剩余未访问的位数长度, p r e 1 pre1 pre1表示前面2位的值, p r e 2 pre2 pre2表示前面1位的值, h a v e have have表示到现在是否存在回文。这DP就已经有了唯一性了。因为 p r e 1 pre1 pre1 p r e 2 pre2 pre2 h a v e have have已经完全表示前面数的状态。

然后 l e n = 0 len=0 len=0时,如果 h a v e = 1 have=1 have=1返回1, h a v e = 0 have=0 have=0返回0.


#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<stdio.h>
#include<map>
#include<queue>
using namespace std;
#define Check(x) cout<<"x:"<<x<<" "
#define Min(x,y,z) min(x,min(z,y))
#define Max(x,y,z) max(x,max(z,y))
typedef long long ll;
const int MAXN = 2e5 + 5;
const int MAXM = 1e6 + 5;
ll n, m;
ll dp[1005][11][11][2];
int digit[1005];
ll mod = 1e9 + 7;;
ll dfs(int len,int pre1,int pre2,bool have, bool limit) {
    if (len == 0) {
        if (!have)return 0;
        else return 1;
    }
    if (!limit && ~dp[len][pre1+1][pre2+1][have])return dp[len][pre1+1][pre2+1][have]%mod;
    int maxx = limit ?  digit[len] : 9;
    ll res = 0;
    for (int i = 0;i <= maxx;i++) {
        bool f = false;
        if (pre1 == i || pre2 == i) {
            f = true;
        }
        if (pre1 == -1 && pre2 == -1 && i == 0)res += dfs(len - 1, -1, -1, 0, limit && i == maxx);
        else res += dfs(len - 1, pre2, i, f || have, limit && i == maxx);
        res %= mod;
    }
    if (!limit)dp[len][pre1+1][pre2+1][have] = res % mod;
    return res%mod;
}
ll solve(string num) {
    int len = num.length();
    for (int i = len - 1;i >= 0;i--)digit[len - i] = num[i] - '0';
    memset(dp, -1, sizeof dp);
    return dfs(len, -1, -1, 0, 1);
}
int main() {
    string a, b;
    cin >> a >> b;
    int pre1 = -1, pre2 = -1;
    bool f = false;
    for (int i = 0;i < a.length();i++) {
        int u = a[i] - '0';
        if (u == pre1 || u == pre2) { f = true;break; }
        pre1 = pre2;
        pre2 = u;
    }
    ll now = (solve(b) - solve(a) + mod) % mod;
    if (f)now++;
    now %= mod;
    cout << now << endl;
}

7.Valley Numer

题目链接:点击此处

求1-r中无山峰的数的个数。

这题很明显的知道我们要用一个标记标记是否存在上坡,不然哪来的山峰。这里我们用 u p up up标记。

之后我们还要有个标记记录上坡后是否存在下坡。这里我们用 h a v e have have来标记。

当然我们比较肯定需要有前一个数字的信息。这里我们用 p r e pre pre记录。

那么DP就很容易写了(要确保唯一性), d p [ l e n ] [ p r e ] [ u p ] [ h a v e ] dp[len][pre][up][have] dp[len][pre][up][have],这里的 p r e , u p , h a v e pre,up,have preuphave已经确保了当前的状态的唯一性了,后面即不会表示多于等于2个不同的状态。

l e n = = 0 len==0 len==0时,如果 h a v e have have返回0,否则返回1。


#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<stdio.h>
#include<map>
#include<queue>
using namespace std;
#define Check(x) cout<<"x:"<<x<<" "
#define Min(x,y,z) min(x,min(z,y))
#define Max(x,y,z) max(x,max(z,y))
typedef long long ll;
const int MAXN = 2e5 + 5;
const int MAXM = 1e6 + 5;
ll n, m;
ll dp[105][11][2][2];
int digit[105];
ll mod = 1e9 + 7;;
ll dfs(int len,int pre,bool up,bool have, bool limit) {
    if (len == 0) {
        if (have)return 0;
        else return 1;
    }
    if (!limit && ~dp[len][pre][up][have])return dp[len][pre][up][have];
    ll ans = 0;
    int maxx = limit ? digit[len] : 9;
    for (int i = 0;i <= maxx;i++) {
        if (pre == -1 && i == 0)ans += dfs(len - 1, -1, 0, 0, limit && i == maxx);
        else  if (pre == -1 && i != 0)ans += dfs(len - 1, i, 0, 0, limit && i == maxx);
        else if (pre != -1) {
            ans += dfs(len - 1, i, i > pre || up, have || (up && i < pre), limit && i == maxx);
        }
        ans %= mod;
    }
    if (!limit)dp[len][pre][up][have] = ans%mod;
    return ans%mod;
}
ll solve(string num) {
    int len = num.length();
    for (int i = len - 1;i >= 0;i--)digit[len - i] = num[i] - '0';
    memset(dp, -1, sizeof dp);
    return dfs(len, -1,0, 0, 1);
}
int main() {
    int t;
    cin >> t;
    while (t--) {
        string a, b;
        cin >> b;
        ll res = (solve(b) -1)% mod;
        cout << res << endl;
    }
}

8. Beautiful numbers

题目链接:点击此处

求[l,r]中一个数能被组成该数的所有非零数整除个数。

很容易知道被一个数的组成数整除,就相当于一个数能被组成数的LCM整除。

那么我们现在想我们上文的2个重要状态。

一个是DP的唯一性,一个len=0时返回什么。

如何定义DP能够让DP唯一标识一个数呢。

d p [ l e n ] [ l c m ] [ s t ] dp[len][lcm][st] dp[len][lcm][st]表示剩余 l e n len len个,哪些遍历过的数的 L C M = l c m LCM=lcm LCM=lcm,一个数取余2520= s t st st。为何取余2520,因为1到9的 L C M LCM LCM为2520,我们一个数能被2520取余为0,那么肯定可以被lcm取余为0。我们这样取可以表示唯一状态而且空间利用小。

l e n = 0 len=0 len=0时,如果 s t % l c m = 0 st\%lcm=0 st%lcm=0,返回1,否则返回0。


#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<stdio.h>
#include<map>
#include<queue>
using namespace std;
#define Check(x) cout<<"x:"<<x<<" "
#define Min(x,y,z) min(x,min(z,y))
#define Max(x,y,z) max(x,max(z,y))
typedef long long ll;
const int MAXN = 2e5 + 5;
const int MAXM = 1e6 + 5;
ll n, m;
ll dp[20][50][2520];
ll digit[105];
ll mod = 0;
int cnt = 0;
inline ll read() {
    ll X = 0, w = 1; char c = getchar();
    while (c < '0' || c>'9') { if (c == '-') w = -1; c = getchar(); }
    while (c >= '0' && c <= '9') X = X * 10 + c - '0', c = getchar();
    return X * w;
}
int GCD(int a, int b) {
    return b == 0 ? a : GCD(b, a % b);
}
int LCM(int a, int b) {
    return a / GCD(a, b) * b;
}
int tong[2521] = { 0 };
void init() {
    for (int i = 1;i <= 2520;i++) {
        if (2520 % i == 0) {  tong[i] = ++cnt; }
    }
}
ll dfs(int len,int lcm,int st,bool limit) {
    if (len == 0) {
        return st % lcm == 0;
    }
    if (!limit && ~dp[len][tong[lcm]][st])return dp[len][tong[lcm]][st];
    int maxx = limit ? digit[len] : 9;
    ll ans = 0;
    for (int i = 0;i <= maxx;i++) {
         int L = (i == 0 ? lcm : LCM(lcm, i));
         ans += dfs(len - 1, L, (st * 10 + i) %2520, limit && i == maxx);
    }
    if (!limit)dp[len][tong[lcm]][st] = ans;
    return ans;
}
ll solve(ll num) {
    int k = 0;
    while (num) {
        digit[++k] = num % 10;
        num /= 10;
    }
    
    return dfs(k,1,0,1);
}
int main() {
    ll t;
    t=read();
    init();
    memset(dp, -1, sizeof dp);
    while(t--){
        ll a,b;
        a = read(), b = read();
        printf("%I64d\n", solve(b) - solve(a - 1)); 
    }
}

9.Magic Number

题目链接:点击此处

这个对于不满足条件的直接continue就行,因为一旦不满足条件,后续不管怎么变都不满足条件。

对于存在前导0的话,我们不能记录dp值。

d p [ l e n ] [ i s e v e n ] [ s t ] dp[len][iseven][st] dp[len][iseven][st]表示了唯一性, l e n len len表示还剩下的位数, i s e v e n iseven iseven表示现在遍历的奇数位还是偶数位, s t st st表示前面所有位的组成数取余 m m m得到的结果。首先前导0肯定不会得到DP值,所以能得到DP的都是非前导0。然后我们不满足条件的 c o n t i u e contiue contiue掉了,所以要DP的值的话,前面肯定是满足条件的。所以,在前面满足条件的情况下,通过看这个数是不是偶数位以及前面数的取模和可以唯一确定DP状态。

l e n = 0 len=0 len=0时,如果 s t = 0 st=0 st=0返回1,否则返回0。


#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<stdio.h>
#include<map>
#include<queue>
using namespace std;
#define Check(x) cout<<"x:"<<x<<" "
#define Min(x,y,z) min(x,min(z,y))
#define Max(x,y,z) max(x,max(z,y))
typedef long long ll;
const int MAXN = 2e5 + 5;
const int MAXM = 1e6 + 5;
int m, d;
ll dp[2005][2][2000];
ll digit[2005];
ll mod = 1e9+7;
ll dfs(int len,int iseven,int topzero,int st,bool limit) {
    if (len == 0) {
        if (st == 0)return 1;
        else return 0;
    }
    if (!limit && !topzero&&~dp[len][iseven][st])return dp[len][iseven][st];
    int maxx = limit ? digit[len] : 9;
    ll ans = 0;
    for (int i = 0;i <= maxx;i++) {
        if (topzero && i == 0)ans += dfs(len - 1, 0, 1, 0, i == maxx && limit);
        else if (topzero && i != 0) {
            if (i == d)continue;
            else {
                ans += dfs(len - 1, 1, 0, i % m, i == maxx && limit);
            }
        }
        else if (!topzero) {
            if ((iseven && i != d) || (!iseven && i == d)) {
                continue;
            }
            ans += dfs(len - 1, iseven ^ 1, 0, (st * 10 + i) % m, i == maxx && limit);
            
        }
        ans %= mod;
    }
    if (!limit&&!topzero)dp[len][iseven][st] = ans;
    return ans;
}
ll solve(string num) {
    int k = 0;
    for (int i = num.length()-1;i >= 0;i--) {
        digit[++k] = num[i]-'0';
    }
    return dfs(k,0,1,0,1);
}
int main() {
    memset(dp, -1, sizeof dp);
    cin >> m >> d;
    string a, b;
    cin >> a >> b;
    ll ans = (solve(b)-solve(a)+mod)%mod;
    int st = 0;
    bool f = true;
    for (int i = 0;i < a.length();i++) {
        int now = a[i] - '0';
        if (((i + 1) % 2 == 0 && now != d) || ((i + 1) % 2 == 1 && now == d)) { f = false;break; }
        st = (st * 10 + now) % m;
    }
    if (st != 0)f = false;
    if (f)ans++;
    ans %= mod;
    cout << ans << endl;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值