zoukankan      html  css  js  c++  java
  • bzoj刷题记录2017.4.2-4.4

    bzoj刷题记录 4.2-4.4


    月考完了。凭借多年应试经验连蒙带猜应付掉,然而坠稳的数学跪烂[没考过班里要学文的dalao]…还是认真刷OJ吧。

    bzoj1211:[HNOI2004]树的计数

    从Zars19的blog里学习了一个prufer编码。经典文章是matrix67 dalao的介绍,传送门
    总之就是把无根有标号树和长度为n2的数组建立了双射,然后树上计数就变成序列计数了。总方案是:

    (n2d11)(n2(d11)d21)(n2(d11)(d21)d31))

    然而直接组合数莫名其妙的跪,于是阶乘展开变成:

    (n2)!i(di1)!

    看到阶乘然后就可以上下分解质因数随便减一减就好。另外特判坑死人。

    #include <bits/stdc++.h>
    using namespace std;
    
    int prime[155], tot = 0;
    int n, s, cnt = 0;
    int c[155];
    
    void get_prime()
    {
        for (int i = 2; i <= n; i++) {
            int flg = 0;
            for (int j = 2; j < i; j++)
                if (i%j == 0) {
                    flg = 1;
                    break;
                }
            if (!flg) {
                prime[++tot] = i;
                for (int j = i; (n-2)/j > 0; j *= i)
                    c[tot] += (n-2)/j;
            }
        }
    }
    
    void div(int nd)
    {
        for (int i = 1; i <= tot; i++) {
            for (int j = prime[i]; j <= nd; j *= prime[i])
                c[i] -= nd/j;
        }
    }
    
    long long power(int a, int n)
    {
        if (n == 0) return 1;
        long long p = power(a, n>>1);
        p *= p, p *= (n&1)?a:1;
        return p;
    }
    
    int main()
    {
        scanf("%d", &n);
        get_prime();
        long long ans = 1;
        if (n == 1) {
            int d; scanf("%d", &d);
            cout << (d == 0) << endl;
            return 0;
        }
        for (int i = 1; i <= n; i++) {
            int d; scanf("%d", &d);
            if (d == 0) {
                cout << 0 << endl;
                return 0;
            }
            div(d-1);
            cnt += d-1;
        }
        if (cnt != n-2) cout << 0 << endl;
        else {
            for (int i = 1; i <= tot; i++) {
                ans *= power(prime[i], c[i]);
            }
            cout << ans << endl;
        }
        return 0;
    }

    bzoj1030:文本生成器

    AC自动机上dp处理不包含任何一个串的方案总数,然后减去就好。
    顺便熟练一波AC自动机。

    #include <bits/stdc++.h>
    using namespace std;
    
    struct ACM {
        struct node {
            bool finish;
            int chl[26], fail;
            node():finish(0),fail(0)
            { memset(chl, 0, sizeof chl); }
        } tree[20005];
        int root, top;
        queue<int> que;
        ACM():root(0),top(0){}
        void push(int &nd, const char *str)
        {
            if (nd == 0) nd = ++top;
            if (*str == '') tree[nd].finish = 1;
            else push(tree[nd].chl[*str-'A'], str+1);
        }
        void push(const char *str) {push(root, str); }
        void init()
        {
            que.push(root); tree[root].fail = 0;
            while (!que.empty()) {
                int tp = que.front(); que.pop();
                tree[tp].finish |= tree[tree[tp].fail].finish;
                for (int i = 0; i < 26; i++) {
                    if (!tree[tp].chl[i]) continue;
                    int nd = tree[tp].fail;
                    while (nd && !tree[nd].chl[i]) nd = tree[nd].fail;
                    tree[tree[tp].chl[i]].fail = nd?tree[nd].chl[i]:root;
                    tree[tree[tp].chl[i]].finish |= tree[tp].finish;
                    que.push(tree[tp].chl[i]);
                }
            }
        }
        void dfs(int nd, int tab = 0)
        {
            if (!nd) return;
            for (int i = 1; i <= tab; i++) putchar(' ');
            printf("%d(%d, %d) : ", nd, tree[nd].fail, tree[nd].finish);
            for (int i = 0; i < 26; i++)
                if (tree[nd].chl[i]) printf("--%c--> %d; ", i+'A', tree[nd].chl[i]);
            puts("");
            for (int i = 0; i < 26; i++)
                if (tree[nd].chl[i]) dfs(tree[nd].chl[i], tab+2);
        }
    } ACM;
    
    int dp[105][20005];
    
    int dfs(int m, int nd)
    {
        if (ACM.tree[nd].finish) return 0;
        if (m == 0) return 1;
        if (dp[m][nd] != -1) return dp[m][nd];
        dp[m][nd] = 0;
        for (int i = 0; i < 26; i++) {
            int p = nd;
            while (p && !ACM.tree[p].chl[i]) p = ACM.tree[p].fail;
            if (p) (dp[m][nd] += dfs(m-1, ACM.tree[p].chl[i])) %= 10007;
            else (dp[m][nd] += dfs(m-1, ACM.root)) %= 10007;
        }
        return dp[m][nd];
    }
    
    int power(int a, int n)
    {
        if (n == 0) return 1;
        int p = power(a, n>>1);
        (p *= p) %= 10007;
        if (n&1) (p *= a) %= 10007;
        return p;
    }
    
    char str[105];
    int n, m;
    
    int main()
    {
        memset(dp, -1, sizeof dp);
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) {
            scanf("%s", str);
            ACM.push(str);
        }
        ACM.init();
        int ans = power(26, m)-dfs(m, ACM.root);
        ((ans %= 10007) += 10007) %= 10007;
        cout << ans << endl;
        return 0;
    }

    bzoj1016:[JSOI2008]最小生成树计数

    原来讲过的题然而一直没有做。
    按边长从小到大排,每次做一个Matrix_Tree生成森林计数,然后把能缩的缩在一起。除了特判1A。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int MAXN = 105, MAXM = 1005;
    struct node {
        int i, j, d;
        friend bool operator < (const node &a, const node &b)
        { return a.d < b.d; }
    } edge[MAXM];
    int n, m;
    int gp[MAXN], vis[MAXN], gt; // 缩在一起的点的新编号
    double g[MAXN][MAXN]; // 求解行列式
    
    struct ufs {
        int fa[MAXN];
        void clear()
        { memset(fa, 0, sizeof fa); }
        ufs(){clear(); }
        inline int findf(int nd)
        { return fa[nd]?fa[nd] = findf(fa[nd]):nd; }
        void link(int i, int j)
        {
            int p = findf(i), q = findf(j);
            if (p != q) fa[p] = q;
        }
    } UFS, u2;
    
    int calc()
    {
        if (gt == 0) return 1;
        gt--;
        double ans = 1;
        for (int i = 1; i <= gt; i++) {
            if (g[i][i] == 0) {
                int k = i+1; while (!g[k][i]) k++;
                swap(g[i], g[k]);
            }
            ans *= g[i][i];
            for (int j = i+1; j <= gt; j++) {
                double t = -g[j][i]/g[i][i];
                for (int k = i; k <= gt; k++)
                    g[j][k] += g[i][k]*t;
            }
        }
        // cout << ans << endl;
        return int(ans+0.05)%31011;
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; i++)
            scanf("%d%d%d", &edge[i].i, &edge[i].j, &edge[i].d);
        sort(edge+1, edge+m+1);
        long long ans = 1;
        for (int i = 1; i <= m; ) {
            // cout << "--" << i <<" " << edge[i].d<< endl;
            int d = edge[i].d;
            memset(vis, 0, sizeof vis);
            memset(g, 0, sizeof g);
            u2.clear();
            gt = 0;
            for (int j = i; j <= m && edge[j].d == d; j++) {
                int p = UFS.findf(edge[j].i), q = UFS.findf(edge[j].j);
                if (p==q) continue;
                if (!vis[p]) gp[p] = ++gt, vis[p] = 1;
                if (!vis[q]) gp[q] = ++gt, vis[q] = 1;
                g[gp[p]][gp[q]]--, g[gp[q]][gp[p]]--, g[gp[p]][gp[p]]++, g[gp[q]][gp[q]]++, u2.link(gp[p], gp[q]);
            } // 建图
            if (gt == 1) break;
            for (int k = 1; k <= gt; k++)
                for (int j = k+1; j <= gt; j++) {
                    // cout << k << " " << j << endl;
                    if (u2.findf(k) != u2.findf(j))
                        u2.link(k, j), g[k][j] = g[j][k] = -1, g[k][k]++, g[j][j]++;
                }
            // 建桥
            (ans *= calc()) %= 31011; // matrix_tree theory
            while (edge[i].d == d) UFS.link(edge[i].i, edge[i].j), i++; // 合并
        }
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                if (UFS.findf(i) != UFS.findf(j)) {
                    cout << 0 << endl;
                    return 0;
                }
        cout << ans << endl;
        return 0;
    }

    bzoj1004: [HNOI2008]Cards

    居然自己看并1A了这置换群…
    首先奇奇怪怪的表述让我们知道出题人要告诉我们是个置换群:

    1. 输入数据保证任意多次洗牌都可用这m种洗牌法中的一种代替——运算封闭;
    2. 置换显然满足结合律、交换律;
    3. 且对每种洗牌法,都存在一种洗牌法使得能回到原状态——每个元素都可逆;
    4. 有没有幺元你加一个不就有了吗?

    然后就可以做波利亚计数了。dp预处理每个置换下不变(环内染一种色)的方案数,求和算平均。为了防止重复置换,加一个哈希判重。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int MAXN = 70;
    int Sr, Sb, Sg, m, p, n;
    int power(int a, int n)
    {
        if (n == 0) return 1;
        int k = power(a, n>>1);
        (k *= k) %= p, (k *= (n&1)?a:1) %= p;
        return k;
    }
    int inv(int a)
    { return power(a, p-2); }
    
    int fa[MAXN], siz[MAXN], per[MAXN];
    inline int findf(int nd)
    { return fa[nd]?fa[nd] = findf(fa[nd]):nd; }
    inline void link(int a, int b)
    {
        int p = findf(a), q = findf(b);
        if (p != q) fa[p] = q, siz[q] += siz[p];
    }
    
    int ht[MAXN], gt = 0;
    int dp[MAXN][21][21][21]; // dp嘛..
    int cnp = 0; // |G| 波利亚计数原理
    
    // ------
    // 哈希表 防止重复而gg
    int hsh[3214567];
    int hash_p(int p[])
    {
        unsigned int val = 0, bs = 1;
        for (int i = 1; i <= n; i++) {
            val += p[i]*bs;
            bs *= (n+1);
        }
        return val%3214567;
    }
    // ------
    
    int val(int pp[MAXN]) // 计算某一置换下不变的方案数, dp
    {
        int k = hash_p(pp);
        if (hsh[k] == 1) return 0;
        else hsh[k] = 1, cnp++;
        memset(fa, 0, sizeof fa);
        for (int i = 1; i <= n; i++) siz[i] = 1;
        for (int i = 1; i <= n; i++) link(i, pp[i]);
        gt = 0;
        for (int i = 1; i <= n; i++)
            if (fa[i] == 0)
                ht[++gt] = siz[i];
        memset(dp, 0, sizeof dp);
        dp[0][0][0][0] = 1;
        for (int i = 1; i <= gt; i++)
            for (int j = 0; j <= Sr; j++)
                for (int k = 0; k <= Sg; k++)
                    for (int l = 0; l <= Sb; l++) {
                        if (j>=ht[i]) (dp[i][j][k][l] += dp[i-1][j-ht[i]][k][l]) %= p;
                        if (k>=ht[i]) (dp[i][j][k][l] += dp[i-1][j][k-ht[i]][l]) %= p;
                        if (l>=ht[i]) (dp[i][j][k][l] += dp[i-1][j][k][l-ht[i]]) %= p;
                    }
        // cout << dp[gt][Sr][Sg][Sb] << endl;
        return dp[gt][Sr][Sg][Sb];
    }
    
    
    int main()
    {
        scanf("%d%d%d%d%d", &Sr, &Sg, &Sb, &m, &p);
        n = Sr + Sg + Sb;
        int ans = 0;
        for (int i = 1; i <= n; i++) per[i] = i; // 加个幺元
        (ans += val(per)) %= p;
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) scanf("%d", &per[j]);
            (ans += val(per)) %= p;
        }
        cout << ans*inv(cnp)%p << endl;
        return 0;
    }

    1007: [HNOI2008]水平可见直线

    水水的半平面交?都是大于号,用一个栈处理就好了,甚至不需要计算几何知识就能脑补1A…五道题打卡下班。

    #include <bits/stdc++.h>
    using namespace std;
    
    struct hp {
        double a, b;
        int id;
        hp(){}
        hp(double x, double y, int i):a(x),b(y),id(i){}
        friend bool operator < (const hp &a, const hp &b)
        { return a.a==b.a?a.b>b.b:a.a < b.a; }
    } sg[50005];
    int n;
    
    stack<int> stk;
    
    int ptw[50005], tp = 0;
    
    bool onleft(const hp &a, const hp &b, const hp &sd)
    {
        double x = (b.b-a.b)/(a.a-b.a), y = a.a*x+a.b;
        return y+1e-7 >= sd.a*x+sd.b;
    }
    
    int main()
    {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            double a, b;
            scanf("%lf%lf", &a, &b);
            sg[i] = hp(a, b, i);
        }
        sort(sg+1, sg+n+1);
        int nw = n;
        for (int i = 1; i <= n; i++)
            if (sg[i].a == sg[i-1].a) {
                sg[i].a = INT_MAX;
                nw--;
            }
        sort(sg+1, sg+n+1);
        n = nw;
        for (int i = 1; i <= n; i++) {
            // cout << sg[i].id << endl;
            while (stk.size() >= 2) {
                int tp = stk.top(); stk.pop();
                int t2 = stk.top(); stk.pop();
                if (onleft(sg[i], sg[t2], sg[tp])) stk.push(t2);
                else {stk.push(t2), stk.push(tp); break;}
            }
            stk.push(i);
        }
        while (!stk.empty()) ptw[++tp] = sg[stk.top()].id, stk.pop();
        sort(ptw+1, ptw+tp+1);
        for (int i = 1; i <= tp; i++)
            printf("%d ", ptw[i]);
        return 0;
    }

    bzoj1015: [JSOI2008]星球大战starwar

    删除难而加入容易,只要反过来做就好了。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int MAXN = 400005, MAXM = 200005;
    struct edge {
        int s, t;
    } graph[MAXM];
    struct node {
        int to, next;
    } edge_list[2*MAXM];
    int head[MAXN], top = 0;
    inline void push(int i, int j)
    { ++top, edge_list[top] = (node) {j, head[i]}, head[i] = top; }
    
    int n, m;
    int q[MAXN], l = 0;
    int fa[MAXN];
    int vis[MAXN], ans[MAXN], cnt, del = 0; // cnt : 联通块个数
    inline int findf(int i)
    { return fa[i]!=-1?fa[i]=findf(fa[i]):i; }
    void link(int i, int j)
    {
        int p = findf(i), q = findf(j);
        if (p != q) {
            fa[p] = q;
            cnt--;
        }
    }
    int main()
    {
        memset(fa, -1, sizeof fa);
        memset(head, -1, sizeof head);
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; i++) {
            scanf("%d%d", &graph[i].s, &graph[i].t);
            push(graph[i].s, graph[i].t), push(graph[i].t, graph[i].s);
        }
        scanf("%d", &l);
        for (int i = 1; i <= l; i++) scanf("%d", &q[i]), vis[q[i]] = i;
        // for (int i = 1; i <= l; i++) cout << vis[q[i]] << " "; puts("");
        cnt = n;
        for (int i = 1; i <= l; i++) del += vis[q[i]] == i;
        for (int i = 1; i <= m; i++)
            if (!vis[graph[i].s] && !vis[graph[i].t])
                link(graph[i].s, graph[i].t);
        for (int i = l; i >= 1; i--) {
            ans[i] = cnt-del;
            // cout << del << endl;
            if (vis[q[i]] == i) {
                del--;
                vis[q[i]] = 0;
                for (int j = head[q[i]]; j != -1; j = edge_list[j].next) {
                    int to = edge_list[j].to;
                    if (vis[to] == 0)
                        link(q[i], to);
                }
            }
        }
        cout << cnt << endl;
        for (int i = 1; i <= l; i++)
            printf("%d
    ", ans[i]);
        return 0;
    }

    bzoj2242: [SDOI2011]计算器

    数论模板题,复习bsgs。
    注意bsgs的第二步求逆要在循环外求,否则会被肉眼可见卡常数。

    #include <bits/stdc++.h>
    using namespace std;
    
    long long y, z, p;
    int t, k;
    long long power(long long a, long long n)
    {
        if (a == 0) return 0;
        if (n == 0) return 1;
        long long k = power(a, n>>1);
        (k *= k) %= p;
        if (n&1) (k *= a) %= p;
        return k;
    }
    long long inv(long long a)
    { return power(a, p-2); }
    
    map<long long, long long> hsh;
    void work()
    {
        if (k == 1) {
            printf("%lld
    ", power(y, z));
        } else if (k == 2) {
            long long x = inv(y)*z%p;
            if (x > 0 && x*y%p == z%p) printf("%lld
    ", x);
            else puts("Orz, I cannot find x!");
        } else {
            y %= p, z %= p;
            if (y == 0 && z == 0) {puts("1");return;}
            if (y == 0) {puts("Orz, I cannot find x!"); return;}
            hsh.clear();
            long long tp = ceil(sqrt(p)+1e-7);
            long long delta = 1;
            for (int i = 1; i <= tp; i++) {
                (delta *= y) %= p;
                if (!hsh.count(delta))hsh[delta] = i;
            }
            long long bs = 1;
            bool fd = 0;
            delta = inv(delta);
            for (int i = 0; i*tp <= p; i++) {
                if (hsh.count(bs*z%p)) {
                    // cout << i*tp << " " << bs << " " << inv(bs) << " " << hsh[inv(bs)] << endl;
                    printf("%lld
    ", i*tp+hsh[bs*z%p]);
                    fd = 1;
                    break;
                }
                (bs *= delta) %= p;
            }
            if (!fd) puts("Orz, I cannot find x!");
        }
    }
    
    int main()
    {
        scanf("%d%d", &t, &k);
        for (int i = 1; i <= t; i++) {
            scanf("%lld%lld%lld", &y, &z, &p);
            work();
        }
        return 0;
    }

    bzoj1014: [JSOI2008]火星人prefix

    一遇数据结构就跪综合症…因为位置和树上位置的转化调了一个多小时。

    首先“插入不超过10000个”可以想到是O(lg2n)的插入,就是二分+哈希了。然而哈希是动态的,于是要splay维护。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int MAXM = 2000005;
    int chl[MAXM][2];
    unsigned long long dat[MAXM], cha[MAXM], power[MAXM];
    unsigned int siz[MAXM], fa[MAXM];
    int top = 0, root = 0;
    inline int new_node(char c, int f)
    { return ++top, dat[top] = cha[top] = c-'a'+1, siz[top] = 1, fa[top] = f, top; }
    
    void update(int nd)
    {
        siz[nd] = siz[chl[nd][0]] + siz[chl[nd][1]] + 1;
        dat[nd] = dat[chl[nd][0]] + power[siz[chl[nd][0]]]*(cha[nd] + (unsigned long long)27*dat[chl[nd][1]]);
    }
    
    void zig(int nd)
    {
        // cout << "zigging : " << nd << endl;
        int p = fa[nd], g = fa[fa[nd]], tp = chl[p][0] != nd;
        int tg = chl[g][0] != p, son = chl[nd][tp^1];
        if (son) fa[son] = p; fa[p] = nd, fa[nd] = g;
        if (g) chl[g][tg] = nd;
        else root = nd;
        chl[nd][tp^1] = p, chl[p][tp] = son;
        update(p), update(nd);
    }
    
    void dfs(int nd, int tab = 0)
    {
        if (!nd) return;
        for (int i = 0; i < tab; i++) cout << " ";
        printf("%d--%c--(%d,%d), siz = %d, fa = %d
    ", nd, cha[nd], chl[nd][0], chl[nd][1], siz[nd], fa[nd]);
        dfs(chl[nd][0], tab+2);
        dfs(chl[nd][1], tab+2);
    }
    
    void splay(int nd, int tar = 0)
    {
        // cout << "splaying : " << nd << " --> son of " << tar << endl;
        while (fa[nd] != tar) {
            // cout << nd << endl;
            int p = fa[nd], g = fa[nd], tp = chl[p][0] != nd, tg = chl[g][0] != p;
            if (fa[p] == tar) {zig(nd); break;}
            if (tp == tg) zig(p), zig(nd);
            else zig(nd), zig(nd);
        }
    } // splay tree
    
    int position(int k)
    {
        if (k > siz[root] || k <= 0) return 0;
        k--;
        int nd = root;
        while (k != siz[chl[nd][0]]) {
            // cout << nd << " " << k << endl;
            nd = (siz[chl[nd][0]] > k) ? (chl[nd][0]) : (k -= siz[chl[nd][0]]+1, chl[nd][1]);
        }
        return nd;
    } // get the position of k-th element
    
    int segment(int l, int r)
    {
        int k = position(l-1), p = position(r+1);
        if (l == 1 && r == siz[root]) return root;
        if (l == 1) return splay(p), chl[root][0];
        if (r == siz[root]) return splay(k), chl[root][1];
        return splay(k), splay(p, root), chl[chl[root][1]][0];
    } // get a segment [l, r]
    
    unsigned long long query(int l, int r)
    { return dat[segment(l, r)]; } // get the hash value in [l, r]
    
    void insert(int k, char c) // push a new element after k-th element
    {
        // cout << k << " " << c << " " << siz[root] << endl;
        if (!root && k == 0) {
            root = new_node(c, 0);
            return;
        } // no element
        if (k == 0) {
            splay(position(1));
            chl[root][0] = new_node(c, root);
            update(root);
        } else {
            int nd = segment(k, k);
            // puts("-----"); dfs(root);
            chl[nd][1] = new_node(c, nd);
            while (nd)
                update(nd), nd = fa[nd];
        }
        // dfs(root);
    }
    
    void change(int k, char c)
    { splay(k), cha[k] = c-'a'+1, update(k);
    } // change the value of an existed element
    
    void init()
    {
        power[0] = 1;
        for (int i = 1; i < MAXM; i++)
            power[i] = power[i-1]*27;
        // power for hash
    }
    // -------------
    
    int ask(int opl, int opr)
    {
        int len = siz[root]; // maxlen
        int l = 0, r = len-max(opl, opr)+1;
        while (l <= r) {
            int mid = (l+r)>>1;
            if (query(opl, opl+mid-1) == query(opr, opr+mid-1)) l = mid+1;
            else r = mid-1;
        }
        return l-1;
    }
    
    int n;
    char str[MAXM];
    
    char get_char()
    {
        char c;
        do c = getchar(); while(!isalpha(c));
        return c;
    }
    
    inline int read() {
        int a = 0, c;
        do c = getchar(); while(!isdigit(c));
        while (isdigit(c)) {
            a = a*10+c-'0';
            c = getchar();
        }
        return a;
    }
    
    int main()
    {
        init();
        scanf("%s", str);
        for (int i = 0, l = strlen(str); i < l; i++)
            insert(i, str[i]); // build a tree
        n = read();
        int cnt = 0;
        for (int i = 1; i <= n; i++) {
            char c = get_char();
            int l, r, p; char d;
            switch (c) {
                case 'Q':
                    cnt++;
                    l = read(), r = read();
                    printf("%d
    ", ask(l, r));
                break;
                case 'R':
                    p = read(), d = get_char();
                    if (!isalpha(d)) throw;
                    change(position(p), d);
                break;
                case 'I':
                    p = read(), d = get_char();
                    if (!isalpha(d)) throw;
                    insert(p, d);
                break;
                default:
                    throw;
                break;
            }
        }
        return 0;
    }
  • 相关阅读:
    6.让代码更具可读性
    5构造函数和析构函数
    4面向对象之类的继承
    3隐形的指针
    2面向对象之类的封装
    od快捷键
    1.纠结的c++
    101宏定义的其他用法
    100解剖宏定义函数
    99,printf scanf手动功能实现
  • 原文地址:https://www.cnblogs.com/ljt12138/p/6684325.html
Copyright © 2011-2022 走看看