省选前的th题

沙茶博主终于整完了知识点并学完了早该在NOIP之前学的知识们

于是终于开始见题了,之前那个奇怪的题单的结果就是这个了

题目按沙茶博主的做题顺序排序

个人感觉(暂时)意义不大的已被自动忽略


洛谷 4917 天守阁的地板

套路(?)反演题,看反演总结

洛谷 4233 射命丸文的笔记

这题好的 orz oscar

推式子+多项式求逆

看那个省选前的多项式总结

洛谷 4918 信仰收集

据说是个套路题,wsl

奇怪的拓扑排序

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=300005,K=55;
 6 int n,m,k,f,b,ma,mb,ca,cb,t1,t2,cnt,ans;
 7 int p[N],noww[N],goal[N],val[N],deg[N],dp[N][K],que[N];
 8 void Maxi(int &x,int y)
 9 {
10     if(x<y) x=y;
11 }
12 void Link(int f,int t)
13 {
14     noww[++cnt]=p[f],p[f]=cnt;
15     goal[cnt]=t,deg[t]++;
16 }
17 int main()
18 {
19     scanf("%d%d%d",&k,&n,&m);
20     scanf("%d%d%d%d",&ma,&mb,&ca,&cb);
21     for(int i=1;i<=k;i++) scanf("%d%d",&t1,&t2),val[t1]+=t2;
22     for(int i=1;i<=m;i++) scanf("%d%d",&t1,&t2),Link(t1,t2);
23     memset(dp,0xc0,sizeof dp);
24     dp[1][0]=val[1],que[f=b=0]=1;
25     for(int i=2;i<=n;i++) if(!deg[i]) que[++b]=i;
26     while(f<=b)
27     {
28         int tn=que[f++];
29         for(int i=p[tn],g;i;i=noww[i])
30         {
31             if(!(--deg[g=goal[i]])) que[++b]=g;
32             Maxi(dp[g][0],dp[tn][ma-1]-ca+val[g]);
33             Maxi(dp[g][0],dp[tn][mb-1]-cb+val[g]);
34             for(int j=1;j<mb;j++) Maxi(dp[g][j],dp[tn][j-1]);
35         }
36     }
37     for(int i=1;i<=n;i++) Maxi(ans,dp[i][0]);
38     printf("%d",ans);
39     return 0;
40 }
View Code

洛谷 3921 小学数学题 

感觉只会2^(2n)+剪枝,咕咕咕

SHOI2016 黑暗前的幻想乡

矩阵树定理+容斥,没啥可说的=。=

 1 #include<cstdio>
 2 #include<vector>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define vpii vector<pair<int,int> >
 6 #define vpit vector<pair<int,int> > ::iterator
 7 using namespace std;
 8 const int N=20,mod=1e9+7;
 9 int n,m,t1,t2,all,ans,tmp,deg[N],mat[N][N]; vpii ve[N];
10 void Add(int &x,int y)
11 {
12     x+=y;
13     if(x>=mod) x-=mod;
14 }
15 int Bitcount(int x)
16 {
17     int ret=0;
18     while(x)
19         ret++,x-=x&-x;
20     return ret;
21 }
22 void exGCD(int a,int b,int &x,int &y)
23 {
24     if(!b) x=1,y=0;
25     else exGCD(b,a%b,y,x),y-=a/b*x;
26 }
27 int Inv(int x)
28 {
29     int xx,yy;
30     exGCD(x,mod,xx,yy);
31     return (xx%mod+mod)%mod;
32 }
33 void Guass()
34 {
35     for(int i=1;i<n;i++)
36         for(int j=1;j<n;j++)
37             if(i!=j)
38             {
39                 int tmp=1ll*mat[j][i]*Inv(mat[i][i])%mod;
40                 for(int k=i;k<=n;k++) 
41                     Add(mat[j][k],mod-1ll*tmp*mat[i][k]%mod);
42             }
43 }
44 int main()
45 {
46     scanf("%d",&n),all=(1<<(n-1))-1;
47     for(int i=1;i<n;i++)
48     {
49         scanf("%d",&m);
50         for(int j=1;j<=m;j++)
51         {
52             scanf("%d%d",&t1,&t2);
53             ve[i].push_back(make_pair(t1,t2));
54         }
55     }
56     for(int i=1;i<=all;i++)
57     {
58         int tmp=1;
59         memset(deg,0,sizeof deg);
60         memset(mat,0,sizeof mat);
61         for(int j=1;j<=n;j++)
62             if(i&(1<<(j-1)))
63                 for(vpit it=ve[j].begin();it!=ve[j].end();it++)
64                 {
65                     int x=it->first,y=it->second;
66                     Add(mat[x][y],mod-1),Add(mat[y][x],mod-1),deg[x]++,deg[y]++;
67                 }
68         for(int j=1;j<=n;j++) mat[j][j]+=deg[j]; Guass();
69         for(int j=1;j<n;j++) tmp=1ll*tmp*mat[j][j]%mod;
70         if((n-1-Bitcount(i))&1) Add(ans,mod-tmp); else Add(ans,tmp);
71     }
72     printf("%d",ans);
73     return 0;
74 }
View Code

ZJOI2015 地震后的幻想乡

神题,orz CLJ

Yousiki的博客好啊

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int M=55,S=(1<<10)+10;
 6 int n,m,t1,t2,all,bit[S],edg[S];
 7 long long C[M][M],unc[S][M],con[S][M];
 8 void Pre()
 9 {
10     all=(1<<n)-1;
11     for(int i=0;i<=m;i++) C[i][0]=1;
12     for(int i=1;i<=m;i++)
13         for(int j=1;j<=i;j++)    
14             C[i][j]=C[i-1][j-1]+C[i-1][j];
15     for(int i=1;i<=all;i++) bit[i]=bit[i>>1]+(i&1);
16 }
17 int main()
18 {
19     scanf("%d%d",&n,&m),Pre();
20     for(int i=1;i<=m;i++)
21     {
22         scanf("%d%d",&t1,&t2);
23         int s=(1<<(t1-1))|(1<<(t2-1));
24         for(int j=0;j<=all;j++)
25             if((j&s)==s) edg[j]++; 
26     }
27     for(int i=0;i<=all;i++)
28         if(bit[i]==1) con[i][0]=1;
29         else
30         {
31             int lbt=i&-i;
32             for(int j=i&(i-1);j;j=(j-1)&i)
33                 if(j&lbt)
34                     for(int k=0;k<=edg[j];k++)
35                         for(int h=0;h<=edg[i^j];h++)
36                             unc[i][k+h]+=con[j][k]*C[edg[i^j]][h];
37             for(int j=0;j<=edg[i];j++)
38                 con[i][j]=C[edg[i]][j]-unc[i][j];
39         }
40     double ans=0;
41     for(int i=0;i<=m;i++)
42         ans+=(1.0*unc[all][i])/(1.0*C[m][i]); 
43     printf("%.6f",ans/(1.0*(m+1)));
44     return 0;
45 }
View Code

ZOJ3522 Hide and seek

YJC -> 秒切人

用LCT把两个端点连成的链提出来(边权转为点权处理),当然我们只需要分别考虑两个点,这里就都按照从下往上走考虑

可以发现如果距离变短了一定是链上一个点下面的都变短了,用LCT维护子树大小(为了维护这个还要要先DFS一遍记录原子树的大小来维护虚儿子的大小),点权和(也就是边权和)每个点上面的下去/下面的上来的距离和(都维护,因为Turnroot的时候会翻转左右子树),这样找到这个分界点就能求答案了。找分解点时把它Splay上去在Splay上面二分走就可以了

  1 #pragma GCC optimize(2)
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define lli long long
  6 using namespace std;
  7 const int N=200005;
  8 int fth[N],son[N][2],rev[N],stk[N];
  9 int p[N],noww[N],goal[N];
 10 int siz[N],vir[N],val[N];
 11 lli sum[N],ups[N],dws[N];
 12 int n,m,t1,t2,t3,cnt,top;
 13 
 14 void Clean()
 15 {
 16     memset(p,cnt=0,sizeof p);
 17     memset(ups,0,sizeof ups);
 18     memset(dws,0,sizeof dws);
 19     memset(fth,0,sizeof fth);
 20     memset(son,0,sizeof son);
 21     memset(rev,0,sizeof rev);
 22     memset(sum,0,sizeof sum);
 23     memset(vir,0,sizeof vir); 
 24     memset(val,0,sizeof val);
 25     memset(siz,0,sizeof siz);
 26 }
 27 
 28 void Link(int f,int t)
 29 {
 30     noww[++cnt]=p[f];
 31     goal[cnt]=t,p[f]=cnt;
 32     noww[++cnt]=p[t];
 33     goal[cnt]=f,p[t]=cnt;
 34 }
 35 void DFS(int nde,int far)
 36 {
 37     fth[nde]=far;
 38     for(int i=p[nde];i;i=noww[i])
 39         if(goal[i]!=far)
 40         {
 41             DFS(goal[i],nde);
 42             siz[nde]+=siz[goal[i]];
 43         }
 44     vir[nde]=siz[nde];
 45 }
 46 
 47 bool Nottop(int nde)
 48 {
 49     int fa=fth[nde];
 50     return son[fa][0]==nde||son[fa][1]==nde;
 51 }
 52 void Release(int nde)
 53 {
 54     if(rev[nde])
 55     {
 56         int &lson=son[nde][0],&rson=son[nde][1];
 57         rev[nde]^=1,rev[lson]^=1,rev[rson]^=1;
 58         swap(ups[nde],dws[nde]),swap(lson,rson);
 59     }
 60 }
 61 void Pushup(int nde)
 62 {
 63     int lson=son[nde][0],rson=son[nde][1];
 64     Release(nde),Release(lson),Release(rson);
 65     sum[nde]=sum[lson]+sum[rson]+val[nde];
 66     siz[nde]=siz[lson]+siz[rson]+vir[nde];
 67     ups[nde]=ups[lson]+ups[rson]+(sum[lson]+val[nde])*siz[rson]+sum[lson]*vir[nde];
 68     dws[nde]=dws[lson]+dws[rson]+(sum[rson]+val[nde])*siz[lson]+sum[rson]*vir[nde];
 69 }
 70 void Rotate(int nde)
 71 {
 72     int fa=fth[nde],gr=fth[fa],isl=nde==son[fa][0];
 73     if(Nottop(fa)) son[gr][fa==gr[son][1]]=nde;
 74     fth[nde]=gr,fth[fa]=nde,fth[son[nde][isl]]=fa;
 75     son[fa][isl^1]=son[nde][isl],son[nde][isl]=fa;
 76     Pushup(fa),Pushup(nde);
 77 }
 78 void Splay(int nde)
 79 {
 80     stk[top=1]=nde;
 81     for(int i=nde;Nottop(i);i=fth[i])
 82         stk[++top]=fth[i];
 83     while(top) Release(stk[top--]);
 84     while(Nottop(nde))
 85     {
 86         int fa=fth[nde],gr=fth[fa];
 87         if(Nottop(fa))
 88             Rotate(((son[fa][0]==nde)==(son[gr][0]==fa))?fa:nde);
 89         Rotate(nde);
 90     }
 91     Pushup(nde);
 92 }
 93 void Access(int nde)
 94 {
 95     int mem=nde,lst=0;
 96     while(nde)
 97     {
 98         Splay(nde);
 99         vir[nde]+=siz[son[nde][1]]-siz[lst];
100         son[nde][1]=lst,Pushup(nde);
101         lst=nde,nde=fth[nde];
102     }
103     Splay(mem);
104 }
105 void Turnroot(int nde)
106 {
107     Access(nde),rev[nde]^=1;
108 }
109 void Split(int x,int y)
110 {
111     Turnroot(x),Access(y);
112 }
113 int Findb(int x,int v)
114 {
115     int ret=-1,nde=x;
116     while(nde)
117     {
118         Release(nde);
119         if((val[nde]+sum[son[nde][0]])*2<=sum[x]+v)
120             v-=(val[nde]+sum[son[nde][0]])*2,ret=nde,nde=son[nde][1];
121         else
122             nde=son[nde][0];
123     }
124     return ret;
125 }
126 lli Query(int x,int y,int v)
127 {
128     if(x!=y) 
129     {
130         Split(x,y);
131         if(sum[y]<=v) return 0;
132         int brd=Findb(y,v);
133         if(brd==-1) return 0; else Splay(brd);
134         return (sum[brd]-v)*siz[son[brd][1]]-dws[son[brd][1]]*2;
135     }
136     else return 0;
137 }
138 
139 int main()
140 {
141     while(scanf("%d",&n)!=EOF)
142     {
143         Clean();
144         for(int i=1;i<n;i++)
145         {
146             scanf("%d%d%d",&t1,&t2,&t3);
147             Link(t1,i+n),Link(i+n,t2);
148             val[i+n]=sum[i+n]=t3;
149         }
150         for(int i=1;i<=n;i++) val[i]=0,siz[i]=1; DFS(1,0);
151         scanf("%d",&m);
152         for(int i=1;i<=m;i++)
153         {
154             scanf("%d%d%d",&t1,&t2,&t3);
155             printf("%lld
",Query(t1,t2,t3)+Query(t2,t1,t3));
156         }
157     }
158     return 0;
159 }
View Code

ZOJ3229 Shoot the Bullet

纯粹复习网络流用的,没啥可看的

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=1500,M=80000,inf=1e9;
 6 int p[N],pp[N],noww[M],goal[M],flow[M];
 7 int dep[N],que[N],ins[N],ots[N],low[M],anss[M];
 8 int n,m,s,t,f,b,ss,tt,rd,id,ll,rr,tar,lim,cnt,ans,num;
 9 void Link(int f,int t,int v)
10 {
11     noww[++cnt]=p[f],p[f]=cnt;
12     goal[cnt]=t,flow[cnt]=v;
13     noww[++cnt]=p[t],p[t]=cnt;
14     goal[cnt]=f,flow[cnt]=0;
15 }
16 void Init()
17 {
18     s=n+m+1,t=s+1,ss=t+1,tt=ss+1,ans=-inf,num=0;
19     memset(p,0,sizeof p),cnt=1;
20     memset(ins,0,sizeof ins);
21     memset(ots,0,sizeof ots);
22 }
23 bool Lay(int st,int ed)
24 {
25     for(int i=1;i<=ed;i++) pp[i]=p[i]; 
26     memset(dep,-1,sizeof dep);
27     que[f=b=0]=st,dep[st]=0;
28     while(f<=b)
29     {
30         int tn=que[f++];
31         for(int i=pp[tn],g;i;i=noww[i])
32             if(flow[i]&&dep[g=goal[i]]==-1)
33                 dep[g]=dep[tn]+1,que[++b]=g;
34     }
35     return ~dep[ed];
36 }
37 int Aug(int nd,int ed,int mn)
38 {
39     if(nd==ed||!mn) return mn;
40     int tmp=0,tep;
41     for(int i=pp[nd],g;i;i=noww[i])
42     {
43         pp[nd]=i;
44         if(dep[g=goal[i]]==dep[nd]+1)
45             if((tep=Aug(g,ed,min(flow[i],mn))))
46             {
47                 flow[i]-=tep,mn-=tep;
48                 flow[i^1]+=tep,tmp+=tep;
49                 if(!mn) break;
50             }
51     }
52     return tmp;
53 }
54 bool Able()
55 {
56     for(int i=p[ss];i;i=noww[i])
57         if(flow[i]) return false;
58     return true;
59 }
60 int main()
61 {
62     while(scanf("%d%d",&n,&m)!=EOF)
63     {
64         Init(),Link(t,s,inf);
65         for(int i=1;i<=m;i++) 
66         {
67             scanf("%d",&rd),Link(i+n,t,inf);
68             ots[i+n]+=rd,ins[t]+=rd; 
69         }
70         for(int i=1;i<=n;i++)
71         {
72             scanf("%d%d",&tar,&lim),Link(s,i,lim);
73             for(int j=1;j<=tar;j++)
74             {
75                 scanf("%d%d%d",&id,&ll,&rr),id++;
76                 Link(i,id+n,rr-ll),low[++num]=ll;
77                 ots[i]+=ll,ins[id+n]+=ll,anss[num]=cnt;
78             }
79         }
80         for(int i=1;i<=t;i++)
81             if(ins[i]-ots[i]<0) Link(i,tt,ots[i]-ins[i]);
82             else Link(ss,i,ins[i]-ots[i]);
83         while(Lay(ss,tt)) Aug(ss,tt,inf); 
84         if(Able())
85         {
86             p[ss]=p[tt]=p[t]=0;
87             while(Lay(s,t)) Aug(s,t,inf);
88             for(int i=p[s];i;i=noww[i]) ans+=flow[i^1];
89             printf("%d
",ans);
90             for(int i=1;i<=num;i++)
91                 printf("%d
",low[i]+flow[anss[i]]);
92         }
93         else puts("-1"); puts("");
94     }
95     return 0;
96 }
View Code

HNOI2015 接水果

DFS序之后变成二维第k大

YJC搞了一个log^3的算法,先DSU on tree+线段树合并把链从一边整合到另一边,然后变成区间第k大

或者好像可以树套树/整体二分+扫描线

这题太tm僵硬了,要是将来有机会再写吧。。。

(你没机会了

COGS2198 帕秋莉的超级多项式

如果我省选没退役,我一定要写一个多项式全家桶.jpg

(你没机会了++

BZOJ 4166-4168

只有第一个可做,因为第二个是没意义的乱搞题,第三个是真·难题

(现在才发现这位奆奆已经过滤了一遍沙茶题和不可做题了(orz),结果我这个沙茶又看了一遍)

月宫的符卡序列

因为不会回文树,于是从这题直接学习回文树的哈希建法,是不是科技点歪了啊。。。

学manacher的时候应该说过本质不同的回文串的数目只有$O(n)$级别

于是朴素的想法当然是把每个回文串都算一遍

优化一下就是我们先算最长的,然后算被它包含的(其实这样形成的这个树形结构就是回文树)

用哈希搞一搞,叶子的权值单独算,非叶子节点的值就是所有儿子的异或和

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<tr1/unordered_map>
 5 #define lli long long
 6 #define umap unordered_map
 7 using namespace std;
 8 using namespace std::tr1;
 9 const int mod1=1e9+7,mod2=2147483647;
10 const int bas1=131,bas2=233,N=1e6+60;
11 char str[N],man[N<<1];
12 int r[N<<1],dp[N],fth[N];
13 int pw1[N],pw2[N],hsh1[N],hsh2[N]; 
14 int T,n,tot,len,mar,mid,ans; umap<lli,int> mp;
15 void Maxi(int &x,int y){if(x<y) x=y;}
16 void Init()
17 {
18     len=strlen(str+1),n=2*len+1;
19     man[0]=')',man[n+1]='(';
20     for(int i=1;i<=n;i++)
21         man[i]=(i&1)?'?':str[i>>1];
22     for(int i=1;i<=len;i++)
23     {
24         hsh1[i]=(1ll*hsh1[i-1]*bas1%mod1+str[i])%mod1;
25         hsh2[i]=(1ll*hsh2[i-1]*bas2%mod2+str[i])%mod2;
26     }
27     memset(r,0,sizeof r);
28     memset(dp,0,sizeof dp);
29     memset(fth,0,sizeof fth);
30     tot=mar=mid=ans=0,mp.clear();
31 }
32 lli Ghash(int l,int r)
33 {
34     int ha1=(hsh1[r]-1ll*hsh1[l-1]*pw1[r-l+1]%mod1+mod1)%mod1;
35     int ha2=(hsh2[r]-1ll*hsh2[l-1]*pw2[r-l+1]%mod2+mod2)%mod2;
36     return ((lli)ha1<<32)+ha2;
37 }
38 int main()
39 {
40     scanf("%d",&T),pw1[0]=pw2[0]=1;
41     for(int i=1;i<=1000000;i++)
42     {
43         pw1[i]=1ll*pw1[i-1]*bas1%mod1;
44         pw2[i]=1ll*pw2[i-1]*bas2%mod2;
45     }
46     while(T--)
47     {
48         scanf("%s",str+1),Init();
49         for(int i=1;i<=n;i++)
50         {
51             r[i]=(mar>=i)?min(mar-i+1,r[2*mid-i]):1;
52             int lst=r[i]==1?0:mp[Ghash((i-r[i])/2+1,(i+r[i]-1)/2)];
53             while(man[i+r[i]]==man[i-r[i]]) 
54             {
55                 r[i]++;
56                 lli hsh=Ghash((i-r[i])/2+1,(i+r[i]-1)/2);
57                 if(!mp.count(hsh)) 
58                 {
59                     mp[hsh]=++tot;
60                     fth[tot]=lst,lst=tot;
61                 }
62                 else lst=mp[hsh];
63             }
64             if(i+r[i]-1>mar) mar=i+r[i]-1,mid=i;
65             if(lst) dp[lst]^=i/2-1;
66         }
67         for(int i=tot;i;i--)
68         {
69             Maxi(ans,dp[i]);
70             dp[fth[i]]^=dp[i];
71         }
72         printf("%d
",ans);
73     } 
74     return 0;
75 }
View Code

BZOJ 2553 禁忌

AC自动机上DP,设$dp[i][j]$表示走了i步在点j的期望伤害,每次在AC自动机上走,走到一个禁忌的结尾就连回根节点和一个虚拟节点,虚拟节点表示可以在这里摸着

矩乘优化一下,然后就卡精度了2333

 1  
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define double long double 
 6 using namespace std;
 7 const int N=105;
 8 int n,alp,len,tot; char rd[N];
 9 int trie[N][26],fail[N],endp[N],que[N],vis[N];
10 struct a
11 {
12     double mat[N][N];
13     void Clean()
14     {
15         memset(mat,0,sizeof mat);
16     }
17 }dp;
18 a Matime(a x,a y)
19 {
20     a ret; ret.Clean();
21     for(int i=0;i<=tot;i++)
22         for(int k=0;k<=tot;k++)
23             for(int j=0;j<=tot;j++)
24                 ret.mat[i][j]+=x.mat[i][k]*y.mat[k][j];
25     return ret;
26 }
27 a Maqpow(a x,int k)
28 {
29     if(k==1) return x;
30     a tmp=Maqpow(x,k>>1);
31     tmp=Matime(tmp,tmp);
32     if(k&1) tmp=Matime(tmp,x);
33     return tmp;
34 }
35 void Insert(char *s)
36 {
37     int len=strlen(s),nde=0;
38     for(int i=0;i<len;i++)
39     {
40         int ch=s[i]-'a';
41         if(!trie[nde][ch]) 
42             trie[nde][ch]=++tot;
43         nde=trie[nde][ch];
44     }
45     endp[nde]=true;
46 }
47 void Create()
48 {
49     int f=0,b=-1,nde=0;
50     for(int i=0;i<alp;i++)
51         if(nde=trie[0][i]) 
52             fail[nde]=0,que[++b]=nde;
53     while(f<=b)
54     {
55         int tn=que[f++];
56         endp[tn]|=endp[fail[tn]];
57         for(int i=0;i<alp;i++)
58             if(nde=trie[tn][i])
59                 fail[nde]=trie[fail[tn]][i],que[++b]=nde;
60             else
61                 trie[tn][i]=trie[fail[tn]][i];
62     }
63 }
64 void Getfunc()
65 {
66     int f=0,b=0,nde=0;
67     double pos=1.0/alp; 
68     vis[que[0]=0]=true;
69     while(f<=b)
70     {
71         int tn=que[f++];
72         for(int i=0;i<alp;i++)
73         {
74             if(!vis[nde=trie[tn][i]])   
75                 vis[nde]=true,que[++b]=nde;
76             if(!endp[nde]) dp.mat[tn][nde]+=pos;
77             else dp.mat[tn][tot]+=pos,dp.mat[tn][0]+=pos;
78         }
79     }
80     dp.mat[tot][tot]=1;
81 }
82 int main()
83 {
84     scanf("%d%d%d",&n,&len,&alp);
85     for(int i=1;i<=n;i++)
86         scanf("%s",rd),Insert(rd);
87     Create(),tot++,Getfunc();
88     dp=Maqpow(dp,len);
89     printf("%.7Lf",dp.mat[0][tot]);
90     return 0;
91 }
View Code

GG COGS凉了,于是暂时就这样吧

( 大 失 败 )

原文地址:https://www.cnblogs.com/ydnhaha/p/10574072.html