比赛:ZJCPC2026(重现赛)
时间:\(2026/7/20\)
赛时 \(6\) 题:

赛后 \(1\) 题:

以下按赛时过题顺序展开:
\(\text{I}\)
给定一矩阵,行内重排,最大化各列最小值之和。
显然各行按从小到大的顺序排序后是最优的,因为此时我们已经实现了对于任意 \(k\),各列最小值中第 \(k\) 大的最大化。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<vector>
#include<array>
#include<random>
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define mkp make_pair
#define pii pair<int,int>
#define cout cerr<<">> ",cout
using namespace std;
const int Mx=1005,p=998244353;
int read(){
int Alice=0,Aya=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') Aya=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
Alice=(Alice<<3)+(Alice<<1)+(ch^48);
ch=getchar();
}
return (Aya==1?Alice:-Alice);
}
int n,m;
int a[Mx][Mx];
void Solve(){
n=read(),m=read();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]=read();
}
sort(a[i]+1,a[i]+m+1);
}
int ans=0;
for(int j=1;j<=m;j++){
int res=1e18;
for(int i=1;i<=n;i++) res=min(res,a[i][j]);
ans+=res;
}
cout<<ans<<endl;
}
signed main(){
int T=read();
while(T--) Solve();
return 0;
}
/*
Hello!!
Sample:
----------------
*/
\(\text{H}\)
给定若干个账号名,判断它是否形如 \(\texttt{ucup-teamXXXX}\)。其中 \(\texttt{XXXX}\) 必须是至少三位且无前导零的十进制正整数。
直接 Check 是否满足格式要求就完了。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<vector>
#include<array>
#include<random>
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define mkp make_pair
#define pii pair<int,int>
#define cout cerr<<">> ",cout
using namespace std;
const int Mx=1005,p=998244353;
int read(){
int Alice=0,Aya=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') Aya=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
Alice=(Alice<<3)+(Alice<<1)+(ch^48);
ch=getchar();
}
return (Aya==1?Alice:-Alice);
}
string s;
void Solve(){
cin>>s;
int n=s.length();
if(n<=11){
puts("NO");
return;
}
string t=s.substr(0,9);
if(t!="ucup-team"){
puts("NO");
return;
}
t=s.substr(9);
//cout<<t<<endl;
if(t[0]=='0'){
puts("NO");
return;
}
for(int i=0;i<(int)t.length();i++){
if(t[i]-'0'>9||t[i]-'0'<0){
puts("NO");
return;
}
}
puts("YES");
}
signed main(){
int T=read();
while(T--) Solve();
return 0;
}
/*
Hello!!
Sample:
5
abcdeabcdeabc
ucup-team761x
ucup-team22xx
ucup-team01236
ucup-team1234567891234567x
----------------
*/
\(\text{G}\)
构造题,在一个长度为 \(n\) 的序列中每一个位置填入 \(X\) 或 \(Y\),使得该序列不存在某一区间和为 \(p\)。
首先 \(p\) 是 \(X\) 或 \(Y\) 的倍数就直接做完了,构造显然。
如果 \(n\) 足够小使得存在一种方案的所有项的和还到不了 \(p\),那也做完了,全填 \(X\) 和 \(Y\) 的较小值即可。
然后就是 \(p\) 为 \(X,Y\) 倍数的情况,然后大力构造:
直觉上,我们尝试让整个序列是循环的,且在循环节中值相同的都挨着,因为这样似乎区间和的种类比较少。
也就是说构造这种循环节:
那整个序列就是这样:
以下不妨设 \(X>Y\):
假设我们在设法构造为 \(p\) 的区间和时选中了红色的部分后再往两侧扩展,那我们可以尽可能地让这些东西的和很大使得一旦再往两边吞并 \(X\) 和就超过 \(p\) 了。
于是,对于循环节,我们构造 $\left \lfloor \dfrac{p}{X}-1 \right \rfloor $ 个 \(X\),$\left \lfloor \dfrac{X-1}{Y} \right \rfloor $ 个 \(Y\),去验证其是否能够达成目的。
造了 \(X,Y\le100\) 的数据发现有点问题,要先把 \(X,Y,p\) 都除以 \(X,Y\) 的 \(\gcd\) 啊,然后又跑了一遍发现所有无解的情况几乎都与样例无解的情况一致,那不就对了嘛,敢猜敢写敢过。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<vector>
#include<array>
#include<random>
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define mkp make_pair
#define pii pair<int,int>
#define cout cerr<<">> ",cout
using namespace std;
const int Mx=1000005,p=998244353;
int read(){
int Alice=0,Aya=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') Aya=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
Alice=(Alice<<3)+(Alice<<1)+(ch^48);
ch=getchar();
}
return (Aya==1?Alice:-Alice);
}
int X,Y;
int n,k;
int w[Mx];
int pre[Mx];
void Solve(){
X=read(),Y=read();
n=read(),k=read();
if(X>Y) swap(X,Y);
if(k%X!=0||n*X<k){
puts("YES");
for(int i=1;i<=n;i++) printf("%lld ",X);
puts("");
return;
}
if(k%Y!=0){
puts("YES");
for(int i=1;i<=n;i++) printf("%lld ",Y);
puts("");
return;
}
int g=__gcd(X,Y);
int X_=X/g,Y_=Y/g,k_=k/g;
unordered_map<int,bool>vis;
int A=k_/X_-1,B=(X_-1)/2;
int D=k_/Y_-1,C=(Y_-1)/2;
// cout<<A<<" "<<B<<endl;
// cout<<C<<" "<<D<<endl;
for(pii _:{mkp(A,B),mkp(C,D)}){
int a=_.fi,b=_.se;
for(int i=1;i<=a;i++) w[i]=X;
for(int i=1+a;i<=a+b;i++) w[i]=Y;
for(int i=a+b+1;i<=n;i++) w[i]=w[i-a-b];
vis.clear();
vis[0]=1;
bool ok=1;
for(int i=1;i<=n;i++){
pre[i]=pre[i-1]+w[i];
vis[pre[i]]=1;
if(pre[i]>=k&&vis[pre[i]-k]){
ok=0;
break;
}
}
if(ok){
puts("YES");
for(int i=1;i<=n;i++) printf("%lld ",w[i]);
puts("");
return;
}
}
puts("NO");
//if(X_<10&&Y_<10&&X_!=k_&&Y_!=k_&&!(X_==1&&Y_==2)) cout<<X_<<" "<<Y_<<" "<<n<<" "<<k_<<endl;
}
signed main(){
//freopen("1.in","r",stdin);
int T=read();
while(T--) Solve();
return 0;
}
/*
Hello!!
Sample:
----------------
*/
\(\text{J}\)
一个矩阵,支持插入行、列(插入的行、列的所有数均为每次给定的值),单点查询。
那行列拆开做不就完了嘛,看看这个位置最后一次是被行操作的还是被列操作的。
行或列拆开之后是单点插入,单点查询,写了块状链表,\(176\text{ms}\) 跑得飞快。
值得一提的是,这东西可以离线下来倒着处理,比如你最后一次插入时其在最终序列里的位置其实是容易确定的,那从后往前依次处理插入的元素在最终序列的位置就行了,然后回答询问用脚做,复杂度线性对数。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<vector>
#include<array>
#include<random>
#include<bits/stdc++.h>
#define fi first
#define se second
#define mkp make_pair
#define pii pair<int,int>
#define cout cerr<<">> ",cout
using namespace std;
const int Mx=500005,p=998244353;
int read(){
int Alice=0,Aya=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') Aya=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
Alice=(Alice<<3)+(Alice<<1)+(ch^48);
ch=getchar();
}
return (Aya==1?Alice:-Alice);
}
int q,C;
struct Opt{
int opt,pos,v;
}op[Mx];
vector<Opt>_,l;
pii ans[Mx][2];
const int B=700;
int No_=0;
vector<pii>ov[Mx];
vector<int>ID;
void Insert(int id,pii v){
int siz=0,O=-1,oid=0;
for(int o:ID){
oid++;
if(siz+(int)ov[o].size()<id){
siz+=ov[o].size();
continue;
}
int pos=id-siz;
ov[o].insert(ov[o].begin()+pos,v);
O=o;
break;
}
if(O==-1){
++No_;
ID.push_back(No_);
ov[No_].push_back(v);
return;
}
if(ov[O].size()>=B+B){
++No_;
ID.insert(ID.begin()+oid,No_);
ov[No_].resize(B);
int tot=B;
for(int i=1;i<=B;i++){
ov[No_][--tot]=ov[O].back();
ov[O].pop_back();
}
}
}
pii Qry(int id){
int siz=0;
for(int o:ID){
if(siz+(int)ov[o].size()<id){
siz+=ov[o].size();
continue;
}
int pos=id-siz;
return ov[o][pos-1];
}
exit(114);
}
signed main(){
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
q=read(),C=read();
_.push_back({0,C,0});
l.push_back({0,C,0});
for(int I=1,opt,pos,v;I<=q;I++){
opt=read(),pos=read(),v=read();
op[I]={opt,pos,v};
}
Insert(0,mkp(C,0));
for(int I=1,opt,pos,v;I<=q;I++){
opt=op[I].opt,pos=op[I].pos,v=op[I].v;
if(opt==1){
Insert(pos,mkp(v,I));
}
if(opt==3){
ans[I][0]=Qry(pos);
//cout<<ans[I][0].fi<<" "<<ans[I][0].se<<endl;
}
}
ID.clear();
for(int i=1;i<=No_;i++) ov[i].clear();
No_=0;
Insert(0,mkp(C,0));
for(int I=1,opt,pos,v;I<=q;I++){
opt=op[I].opt,pos=op[I].pos,v=op[I].v;
if(opt==2){
Insert(pos,mkp(v,I));
}
if(opt==3){
ans[I][1]=Qry(v);
}
}
Insert(0,mkp(C,0));
for(int I=1,opt;I<=q;I++){
opt=op[I].opt;
if(opt==3){
if(ans[I][0].se<ans[I][1].se) printf("%d\n",ans[I][1].fi);
else printf("%d\n",ans[I][0].fi);
}
}
return 0;
}
/*
Hello!!
Sample:
----------------
*/
\(\text{F}\)
给定序列 \(a_i\) 和修改代价 \(c_i\),修改一个位置后可把它改成任意值。求最小代价使得每个前缀和都不是 \(p\) 的倍数。
我们首先发现如果有一个后缀的前缀和如果包含 \(0\sim p-1\) 的所有值那肯定就寄了,必须改点东西才行。而且改了东西之后,从改的这个位置到结尾就都自由了(也就是说,一定合法了),因为我们可以认为改这个位置的时候,其实是在约定到这个位置的前缀和,而因为这个位置我们可以随便改,那改到这个前缀和一定是可以实现的。
于是这启发我们设计 DP:
设 \(f_i\) 为在改 \(a_i\) 的基础上,使后缀 \([i,n]\) 合法的最小代价,那转移就是枚举合法的 \(j\) 使得 \(u\in [i,j]\) 对应的前缀和 \(pre_u\) 模 \(p\) 的值不能覆盖 \(0\sim p-1\),那就有转移:
显然合法的 \(j\) 连续,于是我们只需要找到 \(j\) 的上界即可。这个可以预处理。
然后就是区间最小值,使用你喜欢的数据结构维护即可。
一开始忘了判整个序列可以不通过修改直接合法了,因为我们设计状态时默认有一个位置要被修改了。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<vector>
#include<array>
#include<random>
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define mkp make_pair
#define pii pair<int,int>
using namespace std;
const int Mx=500005;
int read(){
int Alice=0,Aya=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') Aya=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
Alice=(Alice<<3)+(Alice<<1)+(ch^48);
ch=getchar();
}
return (Aya==1?Alice:-Alice);
}
int n,p;
int a[Mx];
int c[Mx];
int nxt[Mx];
int f[Mx];
int r[Mx];
void Solve(){
n=read(),p=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++) c[i]=read();
for(int i=1;i<=n;i++) (a[i]+=a[i-1])%=p;
unordered_map<int,int>lst;
set<int>s;
for(int i=n;i>=1;i--){
if(lst[a[i]]) s.erase(lst[a[i]]);
lst[a[i]]=i,s.insert(lst[a[i]]);
if((int)s.size()<p) r[i]=n;
else{
r[i]=(*prev(s.end()))-1;
}
}
// for(int i=1;i<=n;i++){
// cout<<i<<" "<<r[i]<<endl;
// }
f[n+1]=0;
int R=n;
multiset<int>t;
t.insert(0);
for(int i=n;i>=1;i--){
int res=1e18;
while(R>r[i]){
t.erase(t.find(f[R+1]));
R--;
}
// cout<<t.size()<<endl;
res=*t.begin();
// for(int j=i;j<=r[i];j++){
// res=min(res,f[j+1]);
// }
f[i]=res+c[i];
t.insert(f[i]);
//cout<<i<<" : "<<f[i]<<endl;
}
int ans=1e18;
for(int i=1;i<=n+1;i++){
ans=min(ans,f[i]);
if(a[i]==0) break;
}
cout<<ans<<endl;
}
signed main(){
int T=read();
while(T--) Solve();
return 0;
}
/*
Hello!!
Sample:
----------------
*/
\(\text{L}\)
三维空间中有若干方块,角色每次先按给定向量传送,再在竖直方向自由落体到最高的可站立位置,求从起点到终点的最少传送次数。
这是暴力建图题,按照题意熟练使用 lower_bound 和 upper_bound 把所有方块之间的走法处理出来(这一部分稍有细节,比如可能掉到目标方块上面的方块上或者够不到目标方块之类的),边权为 \(1\),跑 BFS 最短路即可。先实现一个支持三维坐标运算的结构体会方便一些。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<vector>
#include<array>
#include<random>
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define mkp make_pair
#define pii pair<int,int>
#define cout cerr<<">> ",cout
using namespace std;
const int Mx=500005,p=998244353,B=1e9+1;
int read(){
int Alice=0,Aya=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') Aya=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
Alice=(Alice<<3)+(Alice<<1)+(ch^48);
ch=getchar();
}
return (Aya==1?Alice:-Alice);
}
struct Coor{
int x,y,z;
Coor operator +(const Coor&o)const{
int X=x+o.x,Y=y+o.y,Z=z+o.z;
return Coor{X,Y,Z};
}
Coor operator -(const Coor&o)const{
int X=x-o.x,Y=y-o.y,Z=z-o.z;
return Coor{X,Y,Z};
}
bool operator ==(const Coor&o)const{
return (x==o.x&&y==o.y&&z==o.z);
}
bool operator <(const Coor&o)const{
return (x==o.x?y==o.y?z<o.z:y<o.y:x<o.x);
}
}cS,cT,way[Mx],obs[Mx];
int n,m;
Coor down={0,0,-1};
int S,T;
int dis[Mx];
vector<int>e[Mx];
void Solve(){
n=read(),m=read();
for(int i=1;i<=n;i++) e[i].clear(),dis[i]=1e18;
cS.x=read(),cS.y=read(),cS.z=read();
cT.x=read(),cT.y=read(),cT.z=read();
unordered_map<int,set<int> >obsh;
for(int i=1;i<=n;i++){
obs[i].x=read(),obs[i].y=read(),obs[i].z=read();
obsh[obs[i].x*B+obs[i].y].insert(obs[i].z);
if(cS+down==obs[i]) S=i;
if(cT+down==obs[i]) T=i;
}
//cout<<S<<" "<<T<<endl;
unordered_map<int,set<int> >mxh;
unordered_map<int,bool>vis;
for(int i=1;i<=m;i++){
way[i].x=read(),way[i].y=read(),way[i].z=read();
mxh[way[i].x*B+way[i].y].insert(way[i].z);
vis[way[i].x*B+way[i].y]=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
//i -> j
Coor del=obs[j]-obs[i];
if(!vis[del.x*B+del.y]) continue;
auto it=mxh[del.x*B+del.y].lower_bound(del.z);
if(it==mxh[del.x*B+del.y].end()) continue;
int h=*it;
if(h<del.z) continue;
Coor now={obs[j].x,obs[j].y,obs[i].z+h};
//cout<<i<<' '<<j<<" : "<<now.x<<" "<<now.y<<" "<<now.z<<endl;
it=obsh[obs[j].x*B+obs[j].y].upper_bound(obs[j].z);
if(it!=obsh[obs[j].x*B+obs[j].y].end()&&(*it)<=now.z+1){
continue;
}
//cout<<i<<" -> "<<j<<endl;
e[i].push_back(j);
}
}
dis[S]=0;
queue<int>q;
q.push(S);
while(!q.empty()){
int u=q.front();
//cout<<u<<" : "<<dis[u]<<endl;
q.pop();
for(int v:e[u]){
if(dis[v]>dis[u]+1){
dis[v]=dis[u]+1;
q.push(v);
}
}
}
if(dis[T]>=1e18) dis[T]=-1;
cout<<dis[T]<<"\n";
}
signed main(){
int Tc=read();
while(Tc--) Solve();
return 0;
}
/*
Hello!!
Sample:
2
6 4
3 3 3 5 5 5
3 3 2
5 5 4
5 5 7
4 5 5
2 3 2
4 1 1
-1 0 3
2 -2 -1
1 4 9
1 0 0
3 2
0 0 1 1 1 1
0 0 0
1 1 0
1 1 2
1 1 1
1 1 2
----------------
*/
\(\text{M}\)
给定一个排列,对于每个前缀,求出最多能在末尾追加多少个实数,使得新序列元素两两不同,且满足:
和题解思路有点区别。
首先按照树状数组求 LIS 的思路把以 \(a_i\) 结尾的 LIS 和 LDS 长度求出来,分别设为 \(f_{a_i},g_{a_i}\),然后后面接上的那一段序列就有如下约束,形如:
- 开头的数值 \(\ge i\) 的 LIS 长度不超过 \(\text{LIS}(A)-f_i\)
- 开头的数值 \(\le i\) 的 LDS 长度不超过 \(\text{LDS}(A)-g_i\)
那我们的第一想法是分别枚举上下两个约束,然后把对应的长度相乘。因为 LIS 长度与 LDS 的长度之积是序列长度的上界。但是我们发现不对,因为这样可能会有其它约束没有考虑。但是我们可以经过大力猜测和构造得到答案。这是暴力计算答案的代码:
int Calc(){
pre[0]=0;
for(int i=1;i<=n;i++){
pre[i]=max(pre[i-1],f[i]);
}
suf[n+1]=0;
for(int i=n;i>=1;i--){
suf[i]=max(suf[i+1],g[i]);
}
int res=0;
for(int i=1;i<=n;i++){
res+=(pre[n]-pre[i])*(suf[i]-suf[i+1]);
}
return res;
}
然后我们只需要去优化这个东西就可以了!容易发现 \(suf_i-suf_{i+1}\) 为 \(0\) 或 \(1\),那就可以用脚做了(并非)。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<vector>
#include<array>
#include<random>
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define mkp make_pair
#define pii pair<int,int>
using namespace std;
const int Mx=500005,p=998244353;
int read(){
int Alice=0,Aya=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') Aya=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
Alice=(Alice<<3)+(Alice<<1)+(ch^48);
ch=getchar();
}
return (Aya==1?Alice:-Alice);
}
int n;
int a[Mx];
int f[Mx],g[Mx];
struct BIT{
int t[Mx];
void Init(){
for(int i=0;i<=n;i++) t[i]=0;
}
void ChkMax(int i,int k){
for(;i<=n;i+=i&-i) t[i]=max(t[i],k);
}
int Qry(int i){
int res=0;
for(;i;i&=(i-1)) res=max(res,t[i]);
return res;
}
}I,D;
struct BITS{
int t[Mx];
void Init(){
for(int i=0;i<=n;i++) t[i]=0;
}
void Add(int i,int k){
if(i==0) return;
for(;i<=n;i+=i&-i) t[i]+=k;
}
int Qry(int i){
int res=0;
for(;i;i&=(i-1)) res+=t[i];
return res;
}
}C;
int pre[Mx],suf[Mx];
set<int>s;
int Calc(){
pre[0]=0;
for(int i=1;i<=n;i++){
pre[i]=max(pre[i-1],f[i]);
}
int res=0;
for(int i:s){
res+=pre[i];
}
return res;
}
int mxv[Mx],mnv[Mx];
void Solve(){
n=read();
I.Init(),D.Init(),C.Init();
for(int i=1;i<=n;i++) f[i]=0,g[i]=0,mxv[i]=0,mnv[i]=n+1;
for(int i=1;i<=n;i++) a[i]=read();
int LIS=0,LDS=0;
s.clear();
for(int i=1;i<=n;i++) s.insert(0);
int res=0;
for(int i=1;i<=n;i++){
f[a[i]]=I.Qry(a[i])+1;
g[a[i]]=D.Qry(n-a[i]+1)+1;
int v=mxv[g[a[i]]];
int u=mnv[f[a[i]]];
if(u>a[i]){
res+=C.Qry(u-1);
u=mnv[f[a[i]]]=a[i];
res-=C.Qry(u-1);
}
if(v<a[i]){
res-=upper_bound(mnv+1,mnv+n+1,v)-mnv-1;
s.erase(v);
C.Add(v,-1);
v=mxv[g[a[i]]]=a[i];
res+=upper_bound(mnv+1,mnv+n+1,v)-mnv-1;
s.insert(v);
C.Add(v,+1);
}
LIS=max(LIS,f[a[i]]);
LDS=max(LDS,g[a[i]]);
I.ChkMax(a[i],f[a[i]]);
D.ChkMax(n-a[i]+1,g[a[i]]);
//Calc();
printf("%lld ",LIS*LDS-res);
}
puts("");
// for(int i=1;i<=n;i++){
// cout<<f[i]<<" "<<g[i]<<endl;
// }
}
signed main(){
int T=read();
while(T--) Solve();
return 0;
}
/*
Hello!!
Sample:
----------------
*/
\(\text{Summary}\)
总体符合预期,主要是策略上偏保守了,不喜欢吃罚时.jpg
而且那个构造题没有大胆猜测构造的形式,虽然思路是对的但是彷徨了很久,\(\text{L}\) 题写得太慢了,总感觉有一车细节没考虑到,实际上似乎并没有那么多。
浙公网安备 33010602011771号