zoukankan      html  css  js  c++  java
  • 2018冬令营模拟测试赛(一)

    2018冬令营模拟测试赛(一)

    [Problem A]全面战争不可避

    试题描述

    QAQ

    补充说明:铁路毁坏指的是这条铁路彻底消失了,不会对之后的询问造成影响(即询问之间是独立的)

    输入

    TAT

    输出

    Q_Q

    输入示例1

    5 4 4
    1 2
    1 3
    2 4
    2 5
    1 2
    2 4
    3 4
    1 4
    

    输出示例1

    1
    2
    1
    1
    

    输入示例2 & 输出示例2

    戳我下载

    数据规模及约定

    T_T

    题解

    它保证每时每刻都是棵树,那么一条边贡献为 (-1),那么只需要数一下区间内出现了多少个不同的点就好了。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    #define rep(i, s, t) for(int i = (s); i <= (t); i++)
    #define dwn(i, s, t) for(int i = (s); i >= (t); i--)
    
    const int BufferSize = 1 << 16;
    char buffer[BufferSize], *Head, *Tail;
    inline char Getchar() {
    	if(Head == Tail) {
    		int l = fread(buffer, 1, BufferSize, stdin);
    		Tail = (Head = buffer) + l;
    	}
    	return *Head++;
    }
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 500010
    
    int n, m, q, A[maxn<<1], pre[maxn<<1], lst[maxn];
    
    int C[maxn<<1];
    void update(int x) {
    	for(; x <= (m << 1); x += x & -x) C[x]++;
    	return ;
    }
    int sum(int x) {
    	int sum = 0;
    	for(; x; x -= x & -x) sum += C[x];
    	return sum;
    }
    
    struct Que {
    	int ql, qr, id;
    	Que() {}
    	Que(int _1, int _2, int _3): ql(_1), qr(_2), id(_3) {}
    	bool operator < (const Que& t) const { return ql < t.ql; }
    } qs[maxn];
    int Ans[maxn];
    struct Num {
    	int lst, pos;
    	Num() {}
    	Num(int _, int __): lst(_), pos(__) {}
    	bool operator < (const Num& t) const { return lst < t.lst; }
    } ns[maxn<<1];
    
    int num[50], cntn;
    void writeint(int x) {
    	if(!x) return (void)putchar('0');
    	cntn = 0;
    	while(x) num[cntn++] = x % 10, x /= 10;
    	dwn(i, cntn - 1, 0) putchar(num[i] + '0');
    	return ;
    }
    
    int main() {
    	n = read(); m = read(); q = read();
    	rep(i, 1, m) A[(i<<1)-1] = read(), A[i<<1] = read();
    	
    	rep(i, 1, m << 1) ns[i] = Num(lst[A[i]], i), lst[A[i]] = i;
    	rep(kase, 1, q) {
    		int ql = read(), qr = read();
    		qs[kase] = Que(ql, qr, kase);
    	}
    	sort(qs + 1, qs + q + 1); sort(ns + 1, ns + (m << 1 | 1));
    	int j = 1;
    	rep(i, 1, q) {
    		while(j <= (m << 1) && ns[j].lst < (qs[i].ql << 1) - 1) update(ns[j++].pos);
    		Ans[qs[i].id] = sum(qs[i].qr << 1) - sum((qs[i].ql << 1) - 2) - (qs[i].qr - qs[i].ql + 1);
    	}
    	rep(i, 1, q) printf("%d
    ", Ans[i]);
    	
    	return 0;
    }
    

    [Problem B]神社闭店之日

    试题描述

    QAT

    输入

    TAQ

    输出

    Q_T

    输入示例1

    4 3 3 5
    1 2 6 3
    1 1
    2 2
    2 3
    2 4
    3 4
    

    输出示例1

    9
    15
    15
    9
    33
    

    输入示例2 & 输出示例2

    戳我下载

    数据规模及约定

    T_T

    注意:数据范围发生改动,所有 (b_i) 的最小公倍数现在小于等于 (10^{13})

    题解

    首先用一下 KMP 中 border 的理论,不难发现满足要求的串必须是一个周期串,每个最小周期的长度就是所有 (b_i(i in [L_j, R_j])) 和串长的最大公约数;于是现在有了一个暴力,令 (G = mathrm{gcd}{b_i | i in [L_j, R_j]}),则题目就是让求 (sum_{l=1}^L C^{mathrm{gcd}(G, l)})

    这样只能过 (60) 分,考虑优化,显然是枚举 (mathrm{gcd}) 然后用莫比乌斯反演。

    egin{equation}
    sum_{l=1}^L C^{mathrm{gcd}(G, l)} \
    = sum_{g|G} { c^g sum_{g|l, l in [1, L]} {[mathrm{gcd}(G, l) = g]} } \
    = sum_{g|G} { c^g sum_{l=1}^{lfloor frac{L}{g} floor} {[mathrm{gcd}(frac{G}{g}, l) = 1]} } \
    = sum_{g|G} { c^g sum_{l=1}^{lfloor frac{L}{g} floor} { sum_{d|frac{G}{g}, d|l} {mu(d)} } } \
    = sum_{g|G} { c^g sum_{d|frac{G}{g}} { mu(d) sum_{d|l, l in [1, lfloor frac{L}{g} floor]} {1} } } \
    = sum_{g|G} { c^g sum_{gd|G} { mu(d) lfloor frac{L}{gd} floor } } \
    otag
    end{equation}

    此时,令 (T = gd),我们看看能不能消掉一个字母。注意这时 (g|T)

    egin{equation}
    = sum_{g|G} { c^g sum_{T|G, g|T} { mu(frac{T}{g}) lfloor frac{L}{T} floor } } \
    = sum_{T|G} { lfloor frac{L}{T} floor sum_{g|T} {c^g mu(frac{T}{g})} } \
    otag
    end{equation}

    其实字母个数并没有改变(去掉了一个 (d),但引入了 (T)),但是我们可以改变运算顺序了。可以发现,我们将枚举 (T) 放到了外层,这样后面那个 (sum_{g|T} {c^g mu(frac{T}{g})}) 就只与 (T) 有关了,那么对于每一种可能的 (T),我们暴力枚举它的约数 (g),然后算出这个式子的值就好了。

    可以发现后面询问出现的所有约数都是 (mathrm{lcm} { b_i | i in [1, N] }) 的所有约数的真子集,所以我们预处理一下,再用个哈希,就可以 (O(1)) 询问了。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    #define rep(i, s, t) for(int i = (s); i <= (t); i++)
    #define dwn(i, s, t) for(int i = (s); i >= (t); i--)
    #define LL long long
    
    LL read() {
    	LL x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 100010
    #define MOD 998244353
    
    int n, L, C, q;
    LL A[maxn];
    
    LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; }
    
    LL G[maxn<<2];
    void build(int o, int l, int r) {
    	if(l == r) G[o] = A[l];
    	else {
    		int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
    		build(lc, l, mid); build(rc, mid + 1, r);
    		G[o] = gcd(G[lc], G[rc]);
    	}
    	return ;
    }
    LL query(int o, int l, int r, int ql, int qr) {
    	if(ql <= l && r <= qr) return G[o];
    	int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
    	LL ans = 0;
    	if(ql <= mid) ans = gcd(ans, query(lc, l, mid, ql, qr));
    	if(qr > mid) ans = gcd(ans, query(rc, mid + 1, r, ql, qr));
    	return ans;
    }
    
    const int HMOD = 1000037, MAXN = 11010;
    struct Hash {
    	int ToT, head[HMOD], nxt[maxn], val[maxn];
    	LL key[maxn];
    	Hash(): ToT(0) { memset(head, 0, sizeof(head)); }
    	int Find(LL x) {
    		int u = x % HMOD;
    		for(int e = head[u]; e; e = nxt[e]) if(key[e] == x) return val[e];
    		return -1;
    	}
    	void Insert(LL x, int v) {
    		if(Find(x) >= 0) return ;
    		int u = x % HMOD;
    		key[++ToT] = x; val[ToT] = v; nxt[ToT] = head[u]; head[u] = ToT;
    		return ;
    	}
    } cp, mu, Ans;
    
    int Pow(int a, LL b) {
    	int ans = 1, t = a;
    	while(b) {
    		if(b & 1) ans = (LL)ans * t % MOD;
    		t = (LL)t * t % MOD; b >>= 1;
    	}
    	return ans;
    }
    
    int getmu(LL x) {
    	int cur = 1, cnt, m = (int)sqrt(x + .5);
    	rep(i, 2, m) if(x % i == 0) {
    		cnt = 0;
    		while(x % i == 0) {
    			if(++cnt > 1) return 0;
    			x /= i;
    		}
    		cur = -cur;
    		if(x == 1) break;
    	}
    	if(x > 1) cur = -cur;
    	return cur;
    }
    
    int f[MAXN], cd;
    LL divs[MAXN];
    void init(LL x) {
    	int m = (int)sqrt(x + .5);
    	rep(i, 1, m) if(x % i == 0) {
    		divs[++cd] = i;
    		if(i != x / i) divs[++cd] = x / i;
    	}
    	sort(divs + 1, divs + cd + 1);
    	rep(i, 1, cd) cp.Insert(divs[i], Pow(C, divs[i])), mu.Insert(divs[i], getmu(divs[i]));
    	rep(i, 1, cd) {
    		int s = 0;
    		rep(j, 1, i) if(divs[i] % divs[j] == 0) {
    			f[i] += (MOD + mu.Find(divs[i] / divs[j]) * cp.Find(divs[j])) % MOD;
    			if(f[i] >= MOD) f[i] -= MOD;
    			s += (LL)f[j] * (L / divs[j]) % MOD;
    			if(s >= MOD) s -= MOD;
    		}
    		Ans.Insert(divs[i], s);
    	}
    	return ;
    }
    
    int main() {
    	n = read(); L = read(); C = read(); q = read();
    	LL lcm = 1;
    	rep(i, 1, n) A[i] = read(), lcm = lcm / gcd(lcm, A[i]) * A[i];
    	build(1, 1, n);
    	init(lcm);
    	
    	while(q--) {
    		int ql = read(), qr = read();
    		printf("%d
    ", Ans.Find(query(1, 1, n, ql, qr)));
    	}
    	
    	return 0;
    }
    

    [Problem C]唯一神

    试题描述

    QwQ

    ToT

    QwT

    输入

    TwQ

    输出

    TwT

    输入示例1

    2 2 2 0 1 2
    

    输出示例1

    300736801
    

    输入示例2 & 输出示例2

    戳我下载

    数据规模及约定

    T_Q

    Q_T

    题解

    首先不难想到一个 dp,设 (f(i, s, k)) 表示对于前 (i) 行,第 (i) 行的连通状态为 (s)(这个连通状态最多有 (9) 种),当前连通块个数模 (K) 等于 (k) 时的概率。那么你可以预处理一下每两个连通性之间转移对答案的贡献,以及连通块的变化数量。

    但是这样会发现每次修改都不得不重新 dp,非常费时。

    考虑优化,我们发现每一步的转移都是类似的,即从 (f(i, s, k)) 转移到 (f(i+1, s', k + Delta k))(默认 (k) 这一维任何运算都在模 (K) 意义下),这样的话相当于乘上一个 ((maxs cdot K) imes (maxs cdot K))(maxs) 为状态数)的矩阵,于是我们可以用线段树维护这样一个矩阵,每次修改只需要改 (mathrm{log} n) 个矩阵。但是这样做无论是时间还是空间都不够。

    考虑进一步优化,由于每次 (k) 转移到下一步非常有规律,是循环位移了 (Delta k) 个位置,我们就可以想到这是一个多项式循环卷积的形式。

    补充一下循环卷积的定义(形式)和做法:

    定义:令 (f(x) = sum_{i=0}^{K-1} {a_i x^i})(g(x) = sum_{i=0}^{K-1} {b_i x^i}) 为两个 (K-1) 次多项式,那么它们的循环卷积 ((f imes g)(x) = sum_{k=0}^{K-1} { x^k sum_{i+j equiv k (mathrm{mod} K)} {a_i b_j} })

    做法:循环卷积就是在 DFT 的时候开 (K) 位,点值直接对应位相乘,然后再保持 (K) 位并 IDFT 回来,得到的系数向量就是循环卷积之后的结果了。

    由于转化成点值之后,每一步点值都是对应位相乘,所以 (K) 个点值之间互相独立,所以对于每个状态我们维护一下这个点值,再线段树中对于每个点值维护一个 (maxs imes maxs) 的矩阵,那么 dp 的过程就是将最初的状态转化成点值,(F_k) 是一个 (maxs) 维的向量,向量第 (i) 维存储连通状态为 (i) 时的第 (k) 维点值。那个转移矩阵可以这样构造:将每一次转移看成乘上一个 (p cdot x^{Delta k}) 的多项式((p) 是系数,等于该转移贡献的概率),然后将这个多项式转化成点值表达,转移矩阵上对应位置填上对应维度的点值就好了。最后在把最终状态的多项式转化回系数向量即可,答案就是 (k = 0) 那一维。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    #include <map>
    #include <vector>
    using namespace std;
    #define rep(i, s, t) for(int i = (s); i <= (t); i++)
    #define dwn(i, s, t) for(int i = (s); i >= (t); i--)
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 200010
    #define maxs 10
    #define maxk 10
    #define maxnode 400000
    #define MOD 370137601
    #define G 37
    #define LL long long
    
    int n, m, K, q, p0, q0;
    
    map <vector <int>, int> id;
    vector <int> sta[maxs];
    int cnts;
    void search(vector <int> now) {
    	if(id.count(now)) return ;
    	sta[id[now] = ++cnts] = now;
    	rep(i, 0, m - 1)
    		rep(j, i + 1, m - 1) if(now[i] && now[j] && now[i] != now[j]) {
    			vector <int> to = now;
    			int c = min(to[i], to[j]);
    			rep(k, 0, m - 1) if(to[k] == to[i] || to[k] == to[j]) to[k] = c;
    			search(to);
    		}
    	return ;
    }
    int sleep[maxn][3], getup[maxn][3], fa[10], trans[maxs][maxs], tpow[maxs][maxs];
    bool change[maxn][3];
    int findset(int x) { return x == fa[x] ? x : fa[x] = findset(fa[x]); }
    void getTrans() {
    	vector <int> A(m), B(m);
    	rep(sid, 1, cnts) {
    		A = sta[sid];
    		int cn = 0, id1[3], id2[3], cA = 0;
    		memset(id1, 0, sizeof(id1));
    		rep(i, 0, m - 1) if(A[i]) id1[i] = ++cn, cA = max(cA, A[i]);
    		rep(s, 0, (1 << m) - 1) {
    			int cnt = cn;
    			memset(id2, 0, sizeof(id2));
    			rep(i, 0, m - 1) if(s >> i & 1) id2[i] = ++cnt;
    			rep(i, 1, cnt) fa[i] = i;
    			rep(i, 0, m - 1) rep(j, i + 1, m - 1) if(A[i] == A[j] && A[i]) {
    				int u = findset(id1[i]), v = findset(id1[j]);
    				if(u != v) fa[v] = u;
    			}
    			rep(i, 0, m - 1) if(s >> i & 1) {
    				if(A[i]) {
    					int u = findset(id1[i]), v = findset(id2[i]);
    					if(u != v) fa[v] = u;
    				}
    				if(i && (s >> i - 1 & 1)) {
    					int u = findset(id2[i-1]), v = findset(id2[i]);
    					if(u != v) fa[v] = u;
    				}
    			}
    			int c = 0, cB = 0, num[10]; memset(num, 0, sizeof(num));
    			rep(i, 0, m - 1) if(s >> i & 1) {
    				int u = findset(id2[i]);
    				if(!num[u]) num[u] = ++c;
    			}
    			rep(i, 1, cnt) if(findset(i) == i) cB++;
    			rep(i, 0, m - 1) if(s >> i & 1) B[i] = num[findset(id2[i])]; else B[i] = 0;
    			
    			trans[sid][s] = id[B]; tpow[sid][s] = (cB - cA + K) % K;
    		}
    	}
    	return ;
    }
    
    int Pow(int a, int b) {
    	int ans = 1, t = a;
    	while(b) {
    		if(b & 1) ans = (LL)ans * t % MOD;
    		t = (LL)t * t % MOD; b >>= 1;
    	}
    	return ans;
    }
    
    int Mat[maxk][maxk], _Mat[maxk][maxk], wk;
    void FFT_init() {
    	wk = Pow(G, (MOD - 1) / K);
    	rep(i, 0, K - 1) rep(j, 0, K - 1) Mat[i][j] = Pow(wk, i * j), _Mat[i][j] = Pow(Mat[i][j], MOD - 2);
    	return ;
    }
    LL buf[maxs];
    void FFT(int *A, int tp) {
    	memset(buf, 0, sizeof(buf));
    	rep(i, 0, K - 1) {
    		int *M = tp > 0 ? Mat[i] : _Mat[i];
    		rep(j, 0, K - 1) buf[i] += (LL)*(M + j) * A[j] % MOD;
    	}	
    	if(tp < 0) rep(i, 0, K - 1) buf[i] = buf[i] % MOD * Pow(K, MOD - 2);
    	rep(i, 0, K - 1) A[i] = buf[i] % MOD;
    	return ;
    }
    
    struct Matrix {
    	int A[maxs][maxs];
    	Matrix() {}
    	Matrix operator * (const Matrix& t) const {
    		Matrix ans;
    		rep(i, 1, cnts) {
    			memset(buf, 0, sizeof(buf));
    			const int *mA = A[i];
    			rep(k, 1, cnts) {
    				const int *tA = t.A[k];
    				LL tmp = *(mA + k);
    				rep(j, 1, cnts) buf[j] += tmp * *(tA + j) % MOD;
    			}
    			rep(j, 1, cnts) ans.A[i][j] = buf[j] % MOD;
    		}
    		return ans;
    	}
    } Pool[maxnode], Now[maxk];
    int Arr[maxk], F[maxs][maxk];
    int ToT;
    struct SegTree {
    	int node[maxn<<2];
    	void build(int o, int l, int r, int level) {
    		node[o] = level;
    		if(l == r) return ;
    		int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
    		build(lc, l, mid, level - 1); build(rc, mid + 1, r, level - 1);
    		return ;
    	}
    	void modify(int o, int l, int r, int x, int nid) {
    		if(l == r) Pool[node[o] = ++ToT] = Now[nid];
    		else {
    			int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
    			if(x <= mid) modify(lc, l, mid, x, nid); else modify(rc, mid + 1, r, x, nid);
    			Pool[node[o] = ++ToT] = Pool[node[lc]] * Pool[node[rc]];
    		}
    		return ;
    	}
    } sgt[maxk];
    
    int main() {
    	n = read(); m = read(); K = read(); q = read(); p0 = read(); q0 = read();
    	
    	vector <int> A(m);
    	rep(i, 0, (1 << m) - 1) {
    		int c = 0;
    		rep(j, 0, m - 1)
    			if(i >> j & 1) {
    				if(j && (i >> j - 1 & 1)) A[j] = c;
    				else A[j] = ++c;
    			}
    			else A[j] = 0;
    		search(A);
    	}
    	getTrans();
    	
    	FFT_init();
    	int _sleep = (LL)p0 * Pow(q0, MOD - 2) % MOD, _getup = (LL)(q0 - p0) * Pow(q0, MOD - 2) % MOD, clog;
    	for(clog = 1; (1 << clog) <= n; clog++); clog--;
    	ToT = K * (clog + 1);
    	rep(s, 1, cnts) {
    		rep(tr, 0, (1 << m) - 1) {
    			int t = trans[s][tr], p = 1;
    			rep(j, 0, m - 1) if(tr >> j & 1) p = (LL)p * _getup % MOD; else p = (LL)p * _sleep % MOD;
    			memset(Arr, 0, sizeof(Arr));
    			Arr[tpow[s][tr]] = p;
    			FFT(Arr, 1);
    			rep(i, 0, K - 1) Pool[i*(clog+1)+1].A[s][t] = Arr[i];
    		}
    	}
    	rep(i, 0, K - 1) {
    		rep(j, 1, clog) Pool[i*(clog+1)+j+1] = Pool[i*(clog+1)+j] * Pool[i*(clog+1)+j];
    		sgt[i].build(1, 1, n, (i + 1) * (clog + 1));
    	}
    	F[1][0] = 1;
    	FFT(F[1], 1);
    	// F[1~cnts][k] * Pool[sgt[k].node[1]]
    	LL tB[maxs];
    	rep(k, 0, K - 1) {
    		memset(tB, 0, sizeof(tB));
    		rep(i, 1, cnts) {
    			int *pA = Pool[sgt[k].node[1]].A[i];
    			rep(j, 1, cnts)
    				tB[j] += (LL)F[i][k] * *(pA + j) % MOD;
    		}
    		rep(i, 1, cnts) F[i][k] = tB[i] % MOD;
    	}
    	int ans = 0;
    	rep(i, 1, cnts) {
    		FFT(F[i], -1);
    		ans += F[i][0];
    		if(ans >= MOD) ans -= MOD;
    	}
    	printf("%d
    ", ans);
    	
    	while(q--) {
    		int x = read(), y = read() - 1, p1 = read(), q1 = read();
    		change[x][y] = 1;
    		sleep[x][y] = (LL)p1 * Pow(q1, MOD - 2) % MOD; getup[x][y] = (LL)(q1 - p1) * Pow(q1, MOD - 2) % MOD;
    		rep(s, 1, cnts) {
    			rep(tr, 0, (1 << m) - 1) {
    				int t = trans[s][tr], p = 1;
    				rep(j, 0, m - 1)
    					if(tr >> j & 1) p = (LL)p * (change[x][j] ? getup[x][j] : (LL)(q0 - p0) * Pow(q0, MOD - 2) % MOD) % MOD;
    					else p = (LL)p * (change[x][j] ? sleep[x][j] : (LL)p0 * Pow(q0, MOD - 2) % MOD) % MOD;
    				memset(Arr, 0, sizeof(Arr));
    				Arr[tpow[s][tr]] = p;
    				FFT(Arr, 1);
    				rep(i, 0, K - 1) Now[i].A[s][t] = Arr[i];
    			}
    		}
    		rep(i, 0, K - 1) sgt[i].modify(1, 1, n, x, i);
    		
    		memset(F, 0, sizeof(F));
    		F[1][0] = 1;
    		FFT(F[1], 1);
    		// F[1~cnts][k] * Pool[sgt[k].node[1]]
    		rep(k, 0, K - 1) {
    			memset(tB, 0, sizeof(tB));
    			rep(i, 1, cnts) {
    				int *pA = Pool[sgt[k].node[1]].A[i];
    				rep(j, 1, cnts)
    					tB[j] += (LL)F[i][k] * *(pA + j) % MOD;
    			}
    			rep(i, 1, cnts) F[i][k] = tB[i] % MOD;
    		}
    		ans = 0;
    		rep(i, 1, cnts) {
    			FFT(F[i], -1);
    			ans += F[i][0];
    			if(ans >= MOD) ans -= MOD;
    		}
    		printf("%d
    ", ans);
    	}
    	
    	return 0;
    }
    

    又是一道常数卡得生活不能自理的题

  • 相关阅读:
    js-依次循环异步请求(普通/ES6)
    jquery
    js
    selenium
    selenium
    selenium
    python
    selenium
    selenium
    selenium
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/8072010.html
Copyright © 2011-2022 走看看