hash专题

ural1486二维hash

http://acm.timus.ru/problem.aspx?space=1&num=1486

题意:

一个最大500*500的字符矩阵,求最大的两个相同的字符正方形。正方形可以有重叠部分但不能重合。

tip:

二分答案,二分查找正方形的边长,然后使用一个Hash表来判断该边长是否可行。Hash函数二维情况。时间复杂度是O(NMlog(N*M))的。检查是否产生了相同的Hash函数,如果存在相同的Hash函数,则认为该边长可行,否则即认为它不可行。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <map>
using namespace std;
typedef unsigned long long ui;
typedef long long LL;
const int maxn = 510;
const ui MOD = 1e5+7;
int n,m,ans,ans1x,ans2x,ans1y,ans2y;//n行m列
LL cnt;
char s[maxn][maxn];
ui P = 233,Q= 23333,nc[maxn],mc[maxn],h[maxn][maxn];
//P:列上的乘数,Q:行上的乘数
void init(){
    ans =0;
    nc[0] = 1;mc[0] = 1;
    for(int i = 1 ;i <= n ; i++){
        nc[i] = nc[i-1] * P;
        //cout <<"nc"<<nc[i]<<endl;
        mc[i] = mc[i-1] * Q;
    }
    for(int i =  1 ;i <= n ; i++){
        scanf("%s",s[i]+1);
    }
    for(int i = 1; i <= n ; i++){
        //cout<<s[i]+1<<endl;
        for(int j = 1; j <= m ; j++){
            h[i][j] = h[i][j-1]*Q+s[i][j]-'a'+1;//一行的
        }
    }
    for(int i = 2; i <= n ; i++){
        for(int j = 1; j <= m ; j++){
            h[i][j] = h[i][j]+h[i-1][j]*P;//加上前面行的*列的乘数
        }
    }
//    for(int i =  1; i <= n ; i++){
//        for(int j = 1; j <= m ; j++)
//            cout <<h[i][j]<<" ";
//        cout <<endl;
//    }
}

ui gethash(int x1,int x2,int y1,int y2,int mid){
    ui tmp =  h[x2][y2] - h[x1-1][y2]*nc[mid] - h[x2][y1-1]*mc[mid];
    tmp += h[x1-1][y1-1]*nc[mid]*mc[mid];
    return tmp;
}

struct node{
    LL k;
    int x,y;
    ui data;
}book[100010];

bool check(int mid){
    cnt++;
    for(int i = 1; i <= n-mid+1 ; i++){
        for(int j = 1; j <= m-mid+1; j++){
            ui _hash = gethash(i,i+mid-1,j,j+mid-1,mid);
//            if(mid == 3 && i == 1&& j == 1)
//                cout <<"hash1 = "<<_hash<<endl;
//            if(mid == 3&& i == 3 && j == 3)
//                cout<<"hash2 = "<<_hash<<endl;
            ui pos = _hash%MOD;
            if(book[pos].k == cnt&& book[pos].data == _hash){
                if(mid > ans){
                    ans = mid;
                    ans1x = book[pos].x;
                    ans1y = book[pos].y;
                    ans2x = i;
                    ans2y = j;
                }
                return true;
            }
            book[pos].k=cnt;book[pos].x = i;book[pos].y = j;book[pos].data=_hash;
        }

    }
    return false;
}

void sov(){
    int l = 1 ; int r = min(n,m);
    while(l <= r){
       int mid = (l+r)/2;
       //cout <<"md = "<<mid<<endl;
       if(check(mid)){
            l = mid+1;
       }
       else{
            r = mid-1;
       }
    }
    if(ans1x > ans2x){
        swap(ans1x,ans2x);
        swap(ans1y,ans2y);
    }
    if(ans)
        printf("%d\n%d %d\n%d %d\n",ans,ans1x,ans1y,ans2x,ans2y);
    else    printf("0\n");
}

int main(){

    while(~scanf("%d%d",&n,&m)){
        init();
        sov();
    }
}

vijos 有根树同构,图的hash

题意:

判断两个树同构

tip:

转换成判断两个图是否同构,对每个点的度数做hash,迭代(10层?),初始为每个点最开始的度,迭代时用上一次别的点迭代的结果(所有连边的点度数排个序)和这个点的迭代PQ不设成一个。

图的hash还可以距离啊什么

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <map>
using namespace std;
const int maxn =110;
typedef unsigned long long ui;
int a,b,n,T,tot,head[maxn],TAT[maxn],sorthead[maxn],tot2,head2[maxn];
ui d[maxn],tmp[maxn],so[maxn],ans[maxn];
map<ui,int> mp;
ui P = 1e9+7,Q = 1e9+9,X = 3214567;
struct node{
    int v,next;
}edges[maxn],edges2[maxn];

void add(int u,int v){
    edges[tot].v = v;edges[tot].next = head[u];head[u] = tot++;
    edges[tot].v = u;edges[tot].next = head[v];head[v] = tot++;
}
void addt(int u,int v){
    edges[tot].v = v;edges[tot].next = head[u];head[u] = tot++;
}
void add2(int u,int v){
    edges2[tot2].v = v;edges2[tot2].next = head2[u];head2[u] = tot2++;
}
ui gethash(){
    int cl = 10;
    while(cl--){
        for(int i = 1; i <= n ; i++){
            int cnt = 0;
            tmp[i] = 0;
            for(int k = head[i]; k != -1; k = edges[k].next){
                so[cnt++] = d[edges[k].v];
            }
            sort(so,so+cnt);
            for(int j = 0 ; j < cnt ;j++)
                tmp[i] = tmp[i]*P+so[j];
            tmp[i] = tmp[i]+d[i]*Q;
        }

        for(int i = 1; i <= n ; i++){
            d[i] = tmp[i];
        }
    }
    sort(d+1,d+n+1);
    ui no = d[1];
    for(int i = 2; i <= n ; i++)
        no = no*X+d[i];
    return no;
}

void init(){
    scanf("%d%d",&T,&n);
    for(int k = 1; k <= T ; k++){
        tot= 0;
        for(int i = 0; i <= n; i++)
            d[i] = 0,head[i] = -1;
        for(int i = 1; i < n ; i++){
            scanf("%d%d",&a,&b);
            d[a]++;d[b]++;
            add(a,b);
        }
        ans[k] = gethash();
        //cout << ans[k]<<"we"<<endl;
    }
}

void sov(){
    tot = 0;
    for(int i = 0 ; i <= T ;i++)
        head[i] = -1;
    for(int i = 1; i <= T ; i++){
        if(mp[ans[i]]== 0)
            mp[ans[i]] = i;
        addt(mp[ans[i]],i);
            //cout << mp[ans[i]]<<" -."<<i<<endl;
       // cout <<"mp[ "<<ans[i]<<" ] = "<<mp[ans[i]]<<endl;
    }

    int cl = 0;
    for(int i = 0 ; i <= T ;i++)
        head2[i] = -1;
    tot2 = 0;
    for(int i = 1; i <= T ; i++){
        if(mp[ans[i]] == i){
            //cout <<" i = "<<i<<endl;
            for(int p = 0 ;p <= T ;p++) TAT[p] = 0;
            int num = 0;
            for(int k = head[i] ; k != -1; k  = edges[k].next){
                //cout << "i = "<<i <<" next = "<<edges[k].v<<endl;
                TAT[num++] = edges[k].v;
            }

            sort(TAT,TAT+num);
            sorthead[cl++] = TAT[0];
            for(int k = num-1; k >= 1 ; k--)
                add2(TAT[0],TAT[k]);
        }
    }
    sort(sorthead,sorthead+cl);
    for(int i = 0 ; i < cl ; i++){
        printf("%d",sorthead[i]);
        for(int k = head2[sorthead[i]] ; k != -1; k = edges2[k].next)

   printf("=%d",edges2[k].v);
         printf("\n");
    }
}

int main(){
    init();
    sov();
}

uva11996

题意:

题意:给定一个长度为n的01串,你的任务是依次执行如表所示的m条指令:
1 p c 在第p个字符后插入字符,p = 0表示在整个字符串之前插入
2 p 删除第p个字符,后面的字符往前移
3 p1 p2反转第p1到第p2个字符
4 p1 p2输出从p1开始和p2开始的两个后缀的LCP。

tip:

分块,根号(n+m)/2 ~根号(n+m)的长度,维护该块index,left块,right块,里面的字符串,字符串长度,正反hash值。
1.插入,从第一个块开始(首尾添加块0)算长度,找到属于的块,插入,若lenth>根号(n+m) ,把一个块分开,暴力后面块,前面可以直接球出来
若合格,O(lenth)的复杂度重新算hash
2.删除,若太小,则合并,合并两个块只需要O(1), 否则直接删除。。。删除时候O(lenth)
3.反转:若干整块加两边的小块,小块的地方直接暴力,求两个块新的hash值,中间部分直接反转,正反hash掉,然后left块,right块反过来O(lenth)
4.询问,二分当前lenth和,看这么长的字符串hash是否相同,O(1)求多个块合起来的hash 零碎部分暴力O(lenth*logn)

上述复杂度的lenth都是根号n的规模

以下引用论文:
如果两个串不会变化,求LCP只需要求出A+B的后缀数组即可。但是本题的A串是不断变化的,而且由变化的方式可以看出,每次操作都会导致后缀数组发生很大的变化,因此我们应该另辟蹊径。
对于一个k,不难判断两个串的LCP是否有至少k个字符:计算这两个串的前k个字符的Hash值,并且比较它们是否相等。如果相等,就几乎可以肯定地认为这两个串的LCP至少有k个字符,否则,它们的LCP长度肯定不到k。这样,就可以通过二分查找来计算LCP。
现在问题又转化成了怎么求一个子串的Hash。不妨仍然采用Rabin-Karp的Hash函数,如果已知了S1和S2的Hash值,不难求出S1+S2的Hash值:

而 的Hash值显然又是可以在O(n)时间 内预处理的得到的。因此,可以在O(1)时间内通过两个字符串的Hash值得到它们连接后得到的串的Hash值。因此,可以使用块状链表维护计算A中子串的Hash值,方法于维护计算部分和类似,不同之处在于一个字符串正向和反向的Hash值是不同的,为了能在O(n0.5)时间内完成reverse操作,应当要能在O(1)时间内把一个块“反转”,这就要求我们为一个块维护两个Hash值:一个是正向的,一个是倒向的。除此之外的操作于维护部分和或者维护最大值类似。这样,插入,删除,反转操作是O(n0.5)的,而查询操作是O(n0.5logn)的。
类似地,本题的另一种解法是在一棵splay树上维护Hash值。每次一个节点被旋转或以它为根的子树被修改时,则计算它的正向Hash值和反向Hash值,这样,就可以在O(1)时间你reverse一棵子树,通过split可以不难地把一棵子树在均摊O(logn)时间内反转。插入,删除操作显然也是均摊O(logn)的,而查询操作的均摊时间复杂度为O(log2n)

/*
题意:给定一个长度为n的01串,你的任务是依次执行如表所示的m条指令:
1 p c 在第p个字符后插入字符,p = 0表示在整个字符串之前插入
2 p   删除第p个字符,后面的字符往前移
3 p1 p2反转第p1到第p2个字符
4 p1 p2输出从p1开始和p2开始的两个后缀的LCP。
*/
/*
分块,根号(n+m)/2 ~根号(n+m)的长度,维护该块index,left块,right块,里面的字符串,字符串长度,正反hash值。
1.插入,从第一个块开始(首尾添加块0)算长度,找到属于的块,插入,若lenth>根号(n+m) ,把一个块分开,暴力后面块,前面可以直接球出来
若合格,O(lenth)的复杂度重新算hash
2.删除,若太小,则合并,合并两个块只需要O(1), 否则直接删除。。。删除时候O(lenth)
3.反转:若干整块加两边的小块,小块的地方直接暴力,求两个块新的hash值,中间部分直接反转,正反hash掉,然后left块,right块反过来O(lenth)
4.询问,二分当前lenth和,看这么长的字符串hash是否相同,O(1)求多个块合起来的hash 零碎部分暴力O(lenth*logn)

上述复杂度的lenth都是根号n的规模
*/
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
const int maxn = 3000;
const int maxm = 4e6+10;
typedef unsigned long long ui;
ui P = 3,P_power[maxn];
struct node{
    int index,left,right,lenth;
    int is_r;
    ui f_hash,b_hash;
    char s[maxn];
     void roll(){
        if(is_r == 1){
            is_r = 0;
            for(int i = 0 ,j = lenth-1; i <= j; i++,j--)
                swap(s[i],s[j]);
        }
    }
    void print(){
        //roll();
        if(is_r == 0)
        for(int i = 0; i < lenth ; i++) cout <<s[i];
        else
            for(int i = lenth-1; i >= 0 ; i--)  cout <<s[i];
        cout <<endl;
        printf("block[%d].left = %d  right = % d  lenth = %d  f_hash = %d  b_hash = %d\n",index,left,right,lenth,f_hash,b_hash);
    }
    ui getb_hash(){
        ui tmp = 0;
        for(int i = lenth-1 ;i >= 0 ; i--)
            tmp = tmp *P+s[i]-'0'+1;
        return tmp;
    }
    ui getf_hash(){
        ui tmp = 0;
        for(int i = 0 ;i <lenth ; i++)
            tmp = tmp *P+s[i]-'0'+1;
        return tmp;
    }
}block[maxn];

int n,m,low_size,up_size,num_block,cp,pos,num,p1,p2,tot;
char ini[maxm],c[maxn],d[maxn];

void init(){
    scanf("%s",ini);
    up_size = sqrt(n+m);low_size = up_size/2;
    //printf("up _ size = %d   low = %d\n",up_size,low_size);
    block[0].right = 1;num_block = n/low_size;
    int last_size = n-num_block*low_size+low_size;
    int pos = 0;
    //1~倒数第二块
    for(int i = 1; i < num_block ; i++){
        ui tmp = 0,bk = 0;
        block[i].lenth = low_size;block[i].left = i-1;block[i].right = i+1;block[i].index = i;
        for(int j = 0 ;pos < n && j < block[i].lenth;j++, pos++){
            block[i].s[j] = ini[pos];
            tmp = tmp*P+ini[pos]-'0'+1;
        }
        for(int j = block[i].lenth-1; j >= 0; j--)
            bk = bk*P+block[i].s[j]-'0'+1;
        block[i].f_hash = tmp;block[i].b_hash = bk;
        //cout <<"hahahah  "<<block[i].b_hash<<endl;
        block[i].is_r = 0;
    }
    //最后一块
    block[num_block].left = num_block-1;block[num_block].right = maxn-1;block[maxn-1].left = num_block;block[maxn-1].index = maxn-1;
    block[num_block].lenth = last_size;block[num_block].index = num_block;block[num_block].is_r = 0;
    for(int j = 0;pos < n ;j++,pos++){
       block[num_block].s[j] = ini[pos];
    }
    block[num_block].f_hash = block[num_block].f_hash;block[num_block].b_hash = block[num_block].b_hash;
}

void separate(int s_wi){
    ++num_block;
    int l1 = block[s_wi].lenth/2;
    int l2 = block[s_wi].lenth-l1;
    block[num_block].is_r = 0;
    for(int i = l1 ,j = 0; i < block[s_wi].lenth ; i++,j++)   block[num_block].s[j] = block[s_wi].s[i];

    block[num_block].index = num_block;
    block[num_block].left = s_wi;block[num_block].right = block[s_wi].right;block[num_block].lenth = l2;
    block[block[s_wi].right].left = num_block;block[s_wi].right = num_block;block[s_wi].lenth = l1;
    int c1 = s_wi,c2 = num_block;
    block[c1].f_hash = block[c1].getf_hash();
    block[c2].f_hash = block[c2].getf_hash();
    block[c1].b_hash = block[c1].getb_hash();
    block[c2].b_hash = block[c2].getb_hash();
}

void cp1(int pos,int add){
    if(pos == 0){
        block[block[0].right].roll();
        for(int i = block[block[0].right].lenth; i >= 1 ; i--)
            block[block[0].right].s[i] = block[block[0].right].s[i-1];
        block[block[0].right].s[0] = add+'0';
        block[block[0].right].lenth++;
        int c1 = block[0].right;
        block[c1].f_hash = block[c1].getf_hash();
        if(block[block[0].right].lenth > up_size){
            separate(block[0].right);
        }
        return;
    }

    int i,cl = block[0].right;

    while(pos > block[cl].lenth){
        pos-=block[cl].lenth;
        cl = block[cl].right;
    }
    block[cl].roll();
    block[cl].lenth++;
    for(int i = block[cl].lenth; i > pos ; i--)
        block[cl].s[i] = block[cl].s[i-1];
    block[cl].s[pos] = add+'0';
    block[cl].f_hash = block[cl].getf_hash();
    block[cl].b_hash = block[cl].getb_hash();
    if(block[cl].lenth > up_size)   separate(cl);
}
ui get_hash(int len,int p1){
    int c1 = block[0].right;
    int c3,p3 = len+p1-1;

    while(p1 > block[c1].lenth){
        p1 -= block[c1].lenth;
        p3 -= block[c1].lenth;
        c1 = block[c1].right;
    }
    block[c1].roll();
    p1--;//c1块的第p1位置(下标)开始
    c3 = c1;
    while(p3 > block[c3].lenth){
        p3 -= block[c3].lenth;
        c3 = block[c3].right;
    }
    block[c3].roll();
    ui tmp = 0,tp = 0;
    if(c1 == c3){//同一个快
        for(int i = p1 ; i < p3; i++)
            tmp = tmp*P+block[c1].s[i]-'0'+1;
    }
    else{
        for(int i = p1 ;i < block[c1].lenth; i++)   tmp = tmp*P+block[c1].s[i]-'0'+1;
        for(int i = c1 ; i != block[c3].left ;i = block[i].right)   tmp = tmp*P_power[block[block[i].right].lenth]+block[block[i].right].f_hash;
        for(int i = 0 ; i < p3; i++)   tp = tp*P+block[c3].s[i]-'0'+1;
        tmp = tmp*P_power[p3]+tp;
    }
    return tmp;
}

bool se_check(int len,int p1,int p2){
    ui k1 = get_hash(len,p1);
    ui k2 = get_hash(len,p2);
    if(k1 == k2)    return true;
    else    return false;
}

int cp4(int p1,int p2){
    int l = 1, r = tot - p2+1,ans = 0;
    while(l <= r){
        int mid = (l+r)/2;
        if(se_check(mid,p1,p2)){
            ans = max(ans,mid);
            l = mid+1;
        }
        else    r = mid-1;
    }
    return ans;
}

void check(){
    for(int i = block[0].right ; i != maxn-1 ; i= block[i].right){
        block[i].print();
    }
}

void _union(int cl){
    int oth = block[cl].right;
    block[block[oth].right].left = cl;
    block[cl].right = block[oth].right;
    for(int i = block[cl].lenth ,j = 0; j < block[oth].lenth ;i++,j++)
        block[cl].s[i] = block[oth].s[j];
    block[cl].lenth = block[cl].lenth+block[oth].lenth;
    block[cl].f_hash = block[cl].getf_hash();
    block[cl].b_hash = block[cl].getb_hash();
    if(block[cl].lenth > up_size)   separate(cl);
}

void cp2(int pos){
    int cl = block[0].right;

    while(pos > block[cl].lenth){
        pos -= block[cl].lenth;
        cl = block[cl].right;
    }
    block[cl].roll();
    for(int i = pos-1 ;i < block[cl].lenth-1 ; i++){
        block[cl].s[i] = block[cl].s[i+1];
    }
    block[cl].lenth--;
    block[cl].f_hash = block[cl].getf_hash();
    block[cl].b_hash = block[cl].getb_hash();

    if( block[cl].lenth < low_size)  {
        if(block[cl].left == 0 && block[cl].right == maxn-1)    return;
        if(block[cl].right == maxn-1 ){
            block[block[cl].left].roll();
            _union(block[cl].left);
        }
        else {
            block[block[cl].right].roll();
            _union(cl);
        }
    }
}

void cp3(int p1,int p2){
    //check();
    int c1 = block[0].right;
    while(p1 > block[c1].lenth){
        p1 -= block[c1].lenth;
        c1 = block[c1].right;
    }
    block[c1].roll();
    //block[c1].print();
    int c2 = block[0].right;
    while(p2 > block[c2].lenth){
        p2 -= block[c2].lenth;
        c2 = block[c2].right;
    }
    block[c2].roll();
   // block[c2].print();

    if(c1 == c2){
        for(int i = p1-1 ,j = p2-1; i <= j ; i++,j--){
            swap(block[c1].s[i],block[c1].s[j]);
        }
        block[c1].f_hash = block[c1].getf_hash();
        block[c1].b_hash = block[c1].getb_hash();
        return;
    }

    for(int i = block[c1].right ; i != c2; ){
        int j= block[i].right;
        swap(block[i].right,block[i].left);
        swap(block[i].f_hash,block[i].b_hash);
        block[i].is_r ^= 1;
        i = j;
       // cout <"in";
    }
    if(block[c1].right != c2){
        swap(block[c1].right , block[c2].left);
        block[block[c2].left].right = c2;
        block[block[c1].right].left = c1;
    }
    int lenc = 0,lend = 0;

    for(int i = 0 ; i < p1-1;i++)
        c[lenc++] = block[c1].s[i];
    for(int i = p2-1 ; i >= 0 ; i--)
        c[lenc++] = block[c2].s[i];

    for(int i = block[c1].lenth-1; i >= p1-1 ; i--)
        d[lend++] = block[c1].s[i];
    for(int i = p2; i < block[c2].lenth ; i++)
        d[lend++] = block[c2].s[i];
    for(int i = 0 ; i < lenc ; i++){
        //cout <<c[i];
        block[c1].s[i] = c[i];
    }
   // cout <<endl;
    for(int i = 0 ; i < lend ; i++){
        block[c2].s[i] = d[i];
       // cout <<d[i];
    }
   // cout <<endl;
    block[c1].lenth = lenc;block[c2].lenth = lend;
    block[c1].f_hash = block[c1].getf_hash();
    block[c2].f_hash = block[c2].getf_hash();
    block[c1].b_hash = block[c1].getb_hash();
    block[c2].b_hash = block[c2].getb_hash();
   // cout <<"len1 = "<<lenc <<"  lenb = "<<lend<<endl;
    if(lenc > up_size)  separate(c1);
    if(lend > up_size)  separate(c2);
    if(lenc < low_size){
        int cl = c1;
        //block[cl].print();
        if(block[cl].left == 0 && block[cl].right == maxn-1)    return;

        if(block[cl].right == maxn-1 ){
            block[block[cl].left].roll();
            _union(block[cl].left);
        }
        else {
            block[block[cl].right].roll();
            _union(cl);
        }
    }
    if(lend <  low_size){
        int cl = c2;
        if(block[cl].left == 0 && block[cl].right == maxn-1)    return;
        if(block[cl].right == maxn-1 ){
            block[block[cl].left].roll();
            _union(block[cl].left);
        }
        else {
            block[block[cl].right].roll();
            _union(cl);
        }
    }
}

void sov(){
    tot = n;
    for(int ca = 1; ca <= m ; ca++){
        scanf("%d",&cp);
        if(cp == 1){
            tot++;
            scanf("%d%d",&pos,&num);
            cp1(pos,num);
            //check();
        }
        if(cp == 2){
            tot--;
            scanf("%d",&pos);
            cp2(pos);
            //check();
        }
        if(cp == 3){
            scanf("%d%d",&p1,&p2);
            cp3(p1,p2);

            //block[2].print();
            //check();
        }
        if(cp == 4){
            scanf("%d%d",&p1,&p2);
           //    check();
            printf("%d\n",cp4(p1,p2));
        }
    }
}

int main(){
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    P_power[0] = 1;
    for(int i = 1; i < maxn-1 ; i++)
        P_power[i] = P_power[i-1]*P;
    scanf("%d%d",&n,&m);
    init();
    sov();
}
/*
12 100
000100001100
1 0 1
4 2 4
1 1 1
4 3 4
1 1 0
4 2 8
1 3 0
4 3 5
1 7 1
4 6 9
1 8 0
4 1 8
2 8
4 6 9
2 7
4 3 5
2 3
4 2 8
2 1
4 3 4
3 2 9
3 1 3
4 1 7
3 1 2
4 1 8
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值