第十六届北京师范大学程序设计竞赛决赛

B - 外挂使用拒绝

思路:

                dp[k][i] d p [ k ] [ i ] 为:操作 k k 天后第i个账号还有的钱的数量, 那么有以下等式:

dp[k][1]=dp[k1][1]dp[k][2]=dp[k1][2]+dp[k][1]......dp[k][n]=dp[k][n1]+dp[k1][n] { d p [ k ] [ 1 ] = d p [ k − 1 ] [ 1 ] d p [ k ] [ 2 ] = d p [ k − 1 ] [ 2 ] + d p [ k ] [ 1 ] . . . . . . d p [ k ] [ n ] = d p [ k ] [ n − 1 ] + d p [ k − 1 ] [ n ]      ⇒    dp[k1][1]=dp[k][1]dp[k1][2]=dp[k][2]dp[k][1]......dp[k1][n]=dp[k][n]dp[k][n1]   { d p [ k − 1 ] [ 1 ] = d p [ k ] [ 1 ] d p [ k − 1 ] [ 2 ] = d p [ k ] [ 2 ] − d p [ k ] [ 1 ] . . . . . . d p [ k − 1 ] [ n ] = d p [ k ] [ n ] − d p [ k ] [ n − 1 ]
即:
dp[k1][1]dp[k1][2]dp[k1][3]....dp[k1][n] [ d p [ k − 1 ] [ 1 ] d p [ k − 1 ] [ 2 ] d p [ k − 1 ] [ 3 ] . . . . d p [ k − 1 ] [ n ] ] = 110...0011...0001...0...............000...1000...1 [ 1 0 0 . . . 0 0 − 1 1 0 . . . 0 0 0 − 1 1 . . . 0 0 . . . . . . . . . . . . . . . . . . 0 0 0 . . . − 1 1 ] dp[k][1]dp[k][2]dp[k][3]....dp[k][n] [ d p [ k ] [ 1 ] d p [ k ] [ 2 ] d p [ k ] [ 3 ] . . . . d p [ k ] [ n ] ]

那么未修改之前的就是:
[dp[0][1]dp[0][2]dp[0][3]....dp[0][n]] = 110...0011...0001...0...............000...1000...1k [ 1 0 0 . . . 0 0 − 1 1 0 . . . 0 0 0 − 1 1 . . . 0 0 . . . . . . . . . . . . . . . . . . 0 0 0 . . . − 1 1 ] k dp[k][1]dp[k][2]dp[k][3]....dp[k][n] [ d p [ k ] [ 1 ] d p [ k ] [ 2 ] d p [ k ] [ 3 ] . . . . d p [ k ] [ n ] ]
                这个东西本来是矩阵快速幂解决,但是 n n 到了1000,这样的话时间就是 O(n3logk) O ( n 3 log ⁡ k ) ,显然不行,那就打个表出来, 发现了 ... . . . 这个矩阵 k k 次幂之后A[i][j] = (1)ijCijk ( − 1 ) i − j ∗ C k i − j ,这样从 (i,i) ( i , i ) 这个位置往前推,但是组合数很大, 注意 Cxk C k x 可以由 Cx1k C k x − 1 递推而来。

#include<bits/stdc++.h>
typedef long long ll;
const int maxn = 1e3 + 10;
const ll mod = 1e9 + 7;
using namespace std;

ll n, m, T, kase = 1, k;
ll ans[maxn], a[maxn], inv[maxn];

ll qmod(ll x, ll n, ll mod) {
    ll ans = 1;
    for( ; n; n >>= 1) {
        if(n & 1) ans = ans * x % mod;
        x = x * x % mod;
    }
    return ans;
}

int main() {
    for(ll i = 1; i < maxn; i++) inv[i] = qmod(i, mod - 2, mod);
    scanf("%d", &T);
    while(T--){
        scanf("%lld %lld", &n, &k);
        for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
        for(int i = 1; i <= n; i++) {
            ll now = 1; ans[i] = a[i];
            for(int j = i - 1; j >= 1; j--) {
                int flag = (i - j) & 1;
                int res = (i - j);
                now = now * inv[res] % mod;
                now = now * (k - res + 1) % mod;
                if(flag) ans[i] -= now * a[j];
                else ans[i] += now * a[j];
                ans[i] %= mod;
            }
        }
        for(int i = 1; i <= n; i++) {
            if(ans[i] < 0) ans[i] +=mod;
            printf("%lld%c", ans[i], i < n ? ' ' : '\n');
        }
    }
    return 0;
}

D - 雷电爆裂之力

思路:

     最多要经过四条街道, 设 dp[i][j]: d p [ i ] [ j ] : 到达第 i i 条街道中的j这个位置时经过的最短距离,那么到达 j j 这个位置,一种可以从北边向南面走来,一种可以从南面向北面走来,那么有以下两个状态转移方程:
            1从南面向北走到 j j dp[i][j]=min{dp[i1][k]+jk}=min{dp[i1][k]k}+j,其中要保证 k k 这个位置连通第i和第 i1 i − 1 条街道
            2                         2 、 从北面向南走到 j j dp[i][j]=min{dp[i1][k]+kj}=min{dp[i1][k]+k}j,其中要保证 k k 这个位置连通第i和第 i1 i − 1 条街道
                两次分别维护 dp[i1][k][+k d p [ i − 1 ] [ k ] [ + k dp[i1][k]k d p [ i − 1 ] [ k ] − k 前缀的最小值即可。

#include<bits/stdc++.h>
typedef long long ll;
const int maxn = 2e5 + 10;
const ll INF = 1e18;
using namespace std;

int n, m, T, kase = 1, k;
char s[maxn];
ll dp[5][maxn];
ll que[maxn * 4], b[maxn * 4], l, r;
ll a[5][maxn], tot[10];
ll c[5][maxn], d[5];

int main() {
    scanf("%d", &T);
    while(T--) {
        for(int i = 0; i < 3; i++) cin >> tot[i];
        int num = 0; tot[3] = 0;
        for(int i = 0; i < 3; i++) {
            d[i] = tot[i];
            for(int j = 0; j < tot[i]; j++) {
                cin >> a[i][j];
                c[i][j] = a[i][j];
                b[num++] = a[i][j];
            }
            sort(c[i], c[i] + d[i]);
            c[i][d[i]] = INF;
        }

        for(int i = 3; i >= 1; i--) {
            for(int j = 0; j < tot[i - 1]; j++) {
                a[i][tot[i]] = a[i - 1][j];
                tot[i]++;
            }
        }

        for(int i = 0; i < 4; i++) {
            sort(a[i], a[i] + tot[i]);
            tot[i] = unique(a[i], a[i] + tot[i]) - a[i];
        }
        sort(b, b + num);

        num = unique(b, b + num) - b;
        ll ans = INF;
        for(int i = 0; i < 5; i++) {
            for(int j = 0; j < num; j++) dp[i][j] = INF;
        }
        for(int i = 0; i < tot[0]; i++) {
            ll y = a[0][i];
            ll idx = lower_bound(b, b + num, y) - b;
            dp[0][idx] = 0;
        }
        for(int i = 1; i < 4; i++) {
            ///从南向北
            ll m1 = INF, x = 0;
            for(int j = 0; j < tot[i]; j++) {
                int idx = lower_bound(b, b + num, a[i][j]) - b;
                while(x < num && x <= idx) {
                    int rs = b[x], id =lower_bound(c[i - 1], c[i - 1] + d[i - 1], rs) - c[i - 1];
                    if(c[i - 1][id] != rs) { x++; continue; }
                    m1 = min(m1, dp[i - 1][x] - b[x]); x++;
                }
                dp[i][idx] = b[idx] + m1 + 1;
            }
            ///从北向南
            m1 = INF; x = num - 1;
            for(int j = tot[i] - 1; j >= 0; j--) {
                int idx = lower_bound(b, b + num, a[i][j]) - b;
                while(x >= 0 && x >= idx) {
                    int rs = b[x], id = lower_bound(c[i - 1], c[i - 1] + d[i - 1], rs) - c[i - 1];
                    if(c[i - 1][id] != rs) { x--; continue; }
                    m1 = min(m1, dp[i - 1][x] + b[x]); x--;
                }
                dp[i][idx] = min(m1 + 1 - b[idx], dp[i][idx]);
            }
        }
        for(int i = 0; i < num; i++) ans = min(ans, dp[3][i]);
        cout << ans << endl;
    }
    return 0;
}

   

E - 可以来拯救吗

思路:

                因为题目保证了 Ckn100000 C n k ⩽ 100000 ,很显然可以去暴力搜索,要么 n n 很小, 要么min(k,nk)很小, 因为 Ckn=Cnkn C n k = C n n − k ,不能直接对 k k 去搜索, 因为k可能很大,但是取了最小值之后就不会很大了,然后直接搜索就行了。

#include<bits/stdc++.h>
typedef long long ll;
const int maxn = 2e5 + 10;
const ll INF = 1e18;
using namespace std;

struct P {
    int id, tot;
    ll sum;
    P() {}
    P(int id, int t, ll s) :
        id(id), tot(t), sum(s) {}
} res[maxn * 10];
int n, m, T, kase = 1, k;
char s[maxn];
ll a[maxn];

ll solve(int k, int flag, ll su) {
    ll ans = 0, num = 0;
    res[num++] = P(0, 0, 0);
    while(num) {
        P now = res[num - 1]; num--;
        int id = now.id, t = now.tot;
        ll s = now.sum;
        if(t == k) {
            if(flag == 1) ans = ans ^ (s * s);
            else ans = ans ^ ((su - s) * (su - s));
            continue;
        }
        if(t + n - id < k) continue;
        res[num++] = P(id + 1, t, s);
        res[num++] = P(id + 1, t + 1, s + a[id]);
    }
    return ans;
}

void dfs(int id, int k,  int tot, ll sum, ll &ans) {
    if(n - id + tot < k) return ;
    if(tot == k) { ans = ans ^ (sum * sum); return ; }
    dfs(id + 1, k, tot + 1, sum + a[id], ans);
    dfs(id + 1, k, tot, sum, ans);
}

int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d %d", &n, &k);
        ll sum = 0;
        for(int i = 0; i < n; i++) { scanf("%lld", &a[i]); sum += a[i]; }
        int nxt = n - k;
        ll ans;
        if(nxt > k) ans = solve(k, 1, sum);
        else ans = solve(nxt, -1, sum);
        cout << ans << endl;
    }
    return 0;
}

   

F - 汤圆防漏理论

思路:

                记初始状态第 i i 汤圆的粘度为sum[i],有序集合集合里面存入这样的信息:(汤圆的粘度和, 下标),关键字按粘度和排序,那么贪心的思想,为了不让汤圆粘漏,肯定先从粘度和小的粘,即取集合第一个元素,那么答案为每次取的该汤圆的粘度和的最大值。当该元素删除后,与它相连的元素的粘度也随之改变,那么需要先删除集合里现有的那些相连的元素,再插入更新后的情况,时间复杂度 O((n+m)logn). O ( ( n + m ) log ⁡ n ) .

#include<bits/stdc++.h>
typedef long long ll;
const int maxn = 1e5 + 10;
using namespace std;

int n, m, T, kase = 1;

ll sum[maxn], vis[maxn];
typedef pair<ll, ll> pa;
vector<pa> G[maxn];

set<pa> st;
int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d %d", &n, &m);
        for(int i = 0; i < maxn; i++) {
            G[i].clear();
            sum[i] = vis[i] = 0;
        }
        st.clear();
        while(m--) {
            ll x, y, z;
            scanf("%lld %lld %lld", &x, &y, &z);
            G[x].push_back(pa(y, z));
            G[y].push_back(pa(x, z));
            sum[x] += z; sum[y] += z;
        }
        for(ll i = 1; i <= n; i++) st.insert(pa(sum[i], i));
        ll ans = 0;
        while(!st.empty()) {
            set<pa>::iterator it = st.begin();
            pa now = *it; st.erase(it);
            ans = max(ans, now.first);
            ll x = now.second; vis[x] = 1;
            for(int i = 0; i < G[x].size(); i++) {
                pa nxt = G[x][i];
                if(vis[nxt.first]) continue;
                ll u = nxt.first;
                it = st.lower_bound(pa(sum[u], u));
                st.erase(it); sum[u] -= nxt.second;
                st.insert(pa(sum[u], u));
            }
        }
        cout << ans << endl;
    }
    return 0;
}

   

H - 吾好梦中做题

思路:

                如果区间 [l,r] [ l , r ] 是一段合法的括号序列, 那么一定会有对 i[l,r] ∀ i ∈ [ l , r ] ,左括号的数量 totl[i] t o t l [ i ] ⩾ 右括号的数量 totr[i] t o t r [ i ] (自己意会一下), 那么我们记录 sl[i]: s l [ i ] : 区间 [1,i] [ 1 , i ] 的左括号的数量, sr[i]: s r [ i ] : 区间 [1,i] [ 1 , i ] 的右括号的数量。
                那么我们对于查询 x x 这个位置的最长的合法序列的时候,我们就是要找到一个y,使得对 i[x,y] ∀ i ∈ [ x , y ] 有: sl[i]sl[x1]sr[i]sr[x1] s l [ i ] − s l [ x − 1 ] ⩾ s r [ i ] − s r [ x − 1 ] sl[y]sl[x1]=sr[y]sr[x1] s l [ y ] − s l [ x − 1 ] = s r [ y ] − s r [ x − 1 ] ,这样还不好处理,可以移项,得 sl[i]sr[i]sl[x1]sr[x1] s l [ i ] − s r [ i ] ⩾ s l [ x − 1 ] − s r [ x − 1 ] sl[y]sr[y]=sl[x1]sr[x1] s l [ y ] − s r [ y ] = s l [ x − 1 ] − s r [ x − 1 ] ,这样就变成了维护每个位置 i i sl[i]sr[i]的值了,这个容易维护,因为 sl,sr s l , s r 记录的是前缀值,如果第 i i 个位置左括号变右括号,那么区间[i,n]的值都加上 2 − 2 ,反之右括号变左括号就加上 2 2 ,现在考虑怎么找y
                根据分析知道,区间 [x,y] [ x , y ] slsr s l − s r 的最小值就是 sl[x1]sr[x1](sum) s l [ x − 1 ] − s r [ x − 1 ] ( 记 为 s u m ) sl[y]sr[y]=sum s l [ y ] − s r [ y ] = s u m ,线段树维护区间最小值,考虑怎么找 y y 这个位置(x<yn), 线段树中的区间 [l,r] [ l , r ] (节点标号 o o )完全包含在[x,n]时候,区间从左往右考虑,假设该区间最小值是 min m i n ,有三种情况:

  1. min>sum m i n > s u m :如果还没有遇到不合法的情况, 那么还可以往右边扩展,直接返回就行了。
  2. min=sum m i n = s u m :如果还没有遇到不合法的情况, 那么 y y 的位置至少在这里, 记录下线段树的节点fac_node=o,也是直接返回。
  3. min<sum m i n < s u m :出现了这种情况, 知道区间 [l,r] [ l , r ] 一定存在不合法的情况,但是这里要考虑左右两个孩子 o1,o2 o 1 , o 2 节点的最小值 r1,r2 r 1 , r 2 ,如果 r1=sum r 1 = s u m ,那么 fac_node=o1 f a c _ n o d e = o 1 ,最远可能在 o2 o 2 ,递归处理 o2 o 2 ;如果 r1<sum r 1 < s u m ,那么肯定最远只能在 o1 o 1 ,递归处理 o1 o 1 ;否则直接递归处理 o2 o 2 ( C[o]<sum C [ o ] < s u m 考虑完前面的情况后只能 r1>sum r 1 > s u m ,可能可以继续往右扩展)。

                注意情况三不能递归处理两部分, 只能处理一部分,区间最多 logn log ⁡ n 个节点, 完全包含的区间最多往下走 logn log ⁡ n 步, 所以时间复杂度 O(nlog2n) O ( n log 2 ⁡ n )

#include<bits/stdc++.h>
typedef long long ll;
const int maxn = 6e5 + 10;
const int INF = 1e9 + 10;
using namespace std;

int n, m, T, kase = 1;
char s[maxn];
int sl[maxn], sr[maxn];
int C[4 * maxn], laz[4 * maxn];

void build(int o, int l, int r) {
    laz[o] = 0;
    if(l == r) { C[o] = sl[l] - sr[l]; return ; }
    int mid = (l + r) >> 1;
    build(o << 1, l, mid);
    build(o << 1 | 1, mid + 1, r);
    C[o] = min(C[o << 1], C[o << 1 | 1]);
}

void push_down(int o) {
    if(!laz[o]) return ;
    int now = laz[o];
    laz[o << 1] += now;
    laz[o << 1 | 1] += now;
    laz[o] = 0;
    C[o << 1] += now; C[o << 1 | 1] += now;
}

void update(int o, int l, int r, int ql, int qr, int data) {
    if(l > qr || r < ql) return ;
    if(l >= ql && r <= qr) { laz[o] += data; C[o] += data; return ; }
    push_down(o);
    int mid = (l + r) >> 1;
    update(o << 1, l, mid, ql, qr, data);
    update(o << 1 | 1, mid + 1, r, ql, qr, data);
    C[o] = min(C[o << 1], C[o << 1 | 1]);
}

int query_ans(int o, int l, int r, int ind) {
    if(l == r) return C[o];
    int mid = (l + r) >> 1;
    push_down(o);
    if(ind <= mid) return query_ans(o << 1, l, mid, ind);
    else return query_ans(o << 1 | 1, mid + 1, r, ind);
}

int fac_node, l_node, r_node;
void query_max(int o, int l, int r, int ql, int qr, int sum, int &flag, int &ans) {
    if(flag) return ;
    int mid = (l + r) >> 1;
    push_down(o);
    if(l > qr || r < ql) return ;
    if(l >= ql && r <= qr) {
        if(C[o] > sum) return ; ///可以往右扩展
        if(C[o] == sum) {
            if(!flag) { fac_node = o; l_node = l; r_node = r; }
            return ;
        } ///最大可能所在的节点, 并且没有遇到不行的情况
        if(flag) return ;
        if(l == r) { if(C[o] < sum) flag = 1; return ; }
        int r1 = C[o << 1], r2 = C[o << 1 | 1];
        if(r1 == sum) { fac_node = o << 1; l_node = l; r_node = mid; query_max(o << 1 | 1, mid + 1, r, ql, qr, sum, flag, ans);  }
        else if(r1 < sum) query_max(o << 1, l, mid, ql, qr, sum, flag, ans);
        else query_max(o << 1 | 1, mid + 1, r, ql, qr, sum, flag, ans);

        if(C[o] < sum) flag = 1;
        return ;
    }
    query_max(o << 1, l, mid, ql, qr, sum, flag, ans);
    if(flag) return ;
    query_max(o << 1 | 1, mid + 1, r, ql, qr, sum, flag, ans);
}

int query_idx(int o, int l, int r, int sum) {
    if(l == r) return l;
    push_down(o);
    int mid = (l + r) >> 1, o1 = o << 1, o2 = o1 | 1;
    if(C[o2] == sum) return query_idx(o2, mid + 1, r, sum);
    else return query_idx(o1, l, mid, sum);
}

int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d %d", &n, &m);
        scanf("%s", s + 1);
        for(int i = 1; i <= n; i++) {
            if(s[i] == '(') { sl[i] = sl[i - 1] + 1; sr[i] = sr[i - 1]; }
            else { sr[i] = sr[i - 1] + 1; sl[i] = sl[i - 1]; }
        }
        sl[n + 1] = INF; sr[n + 1] = 0;
        build(1, 0, n + 1);
        while(m--) {
            int x, y; scanf("%d %d", &x, &y);
            if(x == 1) {
                if(s[y] == '(') { s[y] = ')'; update(1, 0, n + 1, y, n, -2); }
                else { s[y] = '('; update(1, 0, n + 1, y, n, 2); }
            } else {
                if(s[y] == ')') { puts("0"); continue; }
                int now = query_ans(1, 0, n + 1, y - 1);
                int flag = 0, ans = n + 1;
                fac_node = -1;
                query_max(1, 0, n + 1, y, n + 1, now, flag, ans);
                if(~fac_node) ans = query_idx(fac_node, l_node, r_node, now);
                int tot = query_ans(1, 0, n + 1, ans);
                if(tot == now) printf("%d\n", ans - y + 1);
                else puts("0");
            }
        }
    }
    return 0;
}

K - 好学期来临吧

思路:

                dp[i][0/1][j][k]: d p [ i ] [ 0 / 1 ] [ j ] [ k ] : 只考虑前 i i 个原先计划好的工作, 且第i个工作不选/选, 已经插入了 j j 个新添加的工作(只是用来隔位用的),剩余k个位置对于插入该位置的工作该工作一定可以做到。
                首先可以知道,这 j j 个插入的工作, 一定是快乐值最小的,先对新添加的工作快乐值从小到大排个序,那么这j个工作一定是排好序的前面 j j 个工作,有初始状态dp[1][1][0][0]=a[1],dp[1][0][0][1]=0,因为第一个工作无论选还是不选,首先不用新添加的工作来隔位,但是如果选了,最前面的位置添加一个新工作就不能必定可以选择了,反之不选则 m m 项中的工作插入一项在最前面的话肯可以选择。那么考虑状态转移的时候,有4种情况:

  1. i1 i − 1 个工作选,第 i i 个工作选:要多插入一个新添加的工作,一定可以做的工作数量不变
  2. i1个工作选,第 i i 个工作不选:不需要插入新添加的工作,一定可以做的工作数量也不变
  3. i1个工作不选,第 i i 个工作选:不需要插入新添加的工作,一定可以做的工作数量也不变
  4. i1个工作不选,第 i i 个工作不选:不需要插入新添加的工作,一定可以做的工作数量+1

                现在到达 n n 这个状态,那么对于dp[n][0/1][i][j]:用了 i i 个工作,有j个位置可以必选,那么剩余 mij m − i − j 个工作只能隔位选择了,注意如果第 n n 个工作不选,可供必选的位置+1

#include<bits/stdc++.h>
typedef long long ll;
const int maxn = 1e3 + 10;
const int INF = 2e9 + 19;
using namespace std;

int a[maxn], b[maxn], sum[maxn];
int n, m, T, kase = 1;
int dp[maxn][2][105][105];

int solve(int x, int y) { ///[x + 1, m]的项目有y个一定可以选到
    int res = m - x, ans = 0;
    if(y >= res) return sum[x + 1];
    ans += sum[m - y + 1];  ///最大的y个要选进去
    int l = x + 1, r = m - y; ///[l, r]区间的项目只能间隔取
    int tot = (r - l + 1) / 2;
    int mid = r - tot + 1;
    return ans + sum[mid] - sum[r + 1];
}

int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d %d", &n, &m);
        for(int i = 0; i <= n; i++) {
            for(int j = 0; j <= m; j++) {
                for(int k = 0; k <= m; k++) {
                    dp[i][0][j][k] = -INF;
                    dp[i][1][j][k] = -INF;
                }
            }
        }
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for(int i = 1; i <= m; i++) scanf("%d", &b[i]);
        sort(b + 1, b + m + 1); sum[m + 1] = 0;
        for(int i = m; i >= 1; i--) sum[i] = sum[i + 1] + b[i];
        dp[1][1][0][0] = a[1];  dp[1][0][0][1] = 0;
        for(int i = 2; i <= n; i++) {
            for(int j = 0; j <= m; j++) {
                for(int k = 0; k <= m; k++) {
                    ///选择第i个项目
                    dp[i][1][j][k] = dp[i - 1][0][j][k] + a[i]; ///第i-1个项目不选
                    if(j) dp[i][1][j][k] = max(dp[i - 1][1][j - 1][k] + a[i], dp[i][1][j][k]); ///第i-1个项目也选

                    ///不选择第i个项目
                    dp[i][0][j][k] = max(dp[i - 1][1][j][k], dp[i - 1][0][j][k]); ///第i-1个项目选择
                    if(k) dp[i][0][j][k] = max(dp[i - 1][0][j][k - 1], dp[i][0][j][k]); ///两个都不选,多出一个可供选择的新增的项目
                }
            }
        }
        int ans = 0;
        for(int flag = 0; flag < 2; flag++) {
            for(int i = 0; i <= m; i++) {
                for(int j = 0; j <= m; j++) {
                    int now = dp[n][flag][i][j];
                    ///已经用了i个项目, 还剩j个空位可以插入
                    ans = max(ans, now + solve(i, j + 1 - flag));
                }
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值