ICPC2023济南站题解(A B D E G I K M)

本场队伍整体实力较强,金牌线为低罚时7题。做出8题可稳金牌,这里是难度前8题的题解。

1|0ICPC 2023 济南站


1|1D:


本场签到。

ll T; ll n,m; char s[N]; ll L1,L2,R1,R2; ll qiu(ll u) { ll res = 0; while(u) { res = max(u%10, res); u /= 10; } return res; } int main() { T = read(); while(T--) { L1 = read(); R1 = read(); L2 = read(); R2 = read(); ll R = R1+R2; ll L = L1+L2; if(R-L>10) {cout<<"9\n"; continue;} ll ans = 0; for(ll i=L;i<=R;i++) ans = max(ans,qiu(i)); cout<<ans<<endl; } return 0; }

1|2I:


可以区间排序,那么肯定是贪心地找最大的区间。

正解就是从左到右,遇到 aii 的位置就找最右边第一个小于 ai 的位置,将区间排序。

复杂度n方绰绰有余,正确性证明:每次至少能排好两个数的位置,即当前位置 i 和 i+1。可以满足题目 n2 的要求。

ll T; ll n,m; int a[N]; int L[N],R[N],cnt; int main() { T = read(); while(T--) { cnt = 0; n = read(); for(int i=1;i<=n;i++) a[i] = read(); for(int i=1;i<=n;i++) { if(a[i]==i) continue; for(int j=n;j>i;j--) { if(a[j]<a[i]) { L[++cnt] = i; R[cnt] = j; sort(a+i,a+j+1); break; } } } cout<<cnt<<endl; for(int i=1;i<=cnt;i++) cout<<L[i]<<" "<<R[i]<<endl; } return 0; }

1|3A:


感觉官方题解写的有点问题?说下我觉得更简单的思路。

首先题目保证了必定是合法的括号序列,如果不保证的话怎么判断是否合法:依旧是用一个栈,由于没有左右括号区分,我们用贪心的思想,如果栈顶与当前位置括号相同就出栈,否则入栈。如果是有唯一方案,那就是这种方案,方案不唯一的话说明有的位置可以不出栈。

为了表述方便,我们将形如 ([([])]) 连续嵌套的括号序列称为 “小山峰”,注:必须是两种括号交替才算,比如 (()) 认为是两个小山峰,因为可以变成 ()()

本题结论就是,所有合法的序列最多有两个独立的小山峰,一个最外层为方括号另一个为圆括号,如 ([]) [([()])]

证明:

首先两个相邻的小山峰最外层括号不能一致,否则翻转最中间的两个就会出现第二种情况,例:([()]) ([]) 变成([()]( )[])

其次不能有三个小山峰左右排列在一起,由上面第一条知道,第一个和第三个小山峰最外层是一致的。翻转第一个小山峰最右边的括号和第三个小山峰最左边的括号,就会出现第二种情况,例:() [] ([])变成(( [] )[])

然后是一个括号内不能包含多个小山峰或单个符号相同的小山峰:原因也很简单,如果括号内有多个小山峰,必定会有一个小山峰最外层可以翻转,例:单个符号相同( ([]) )变成( )[]( ),包含两个( [()] () )变成( [()] )( )

综上,合法的所有情况就是最多两个小山峰,一左一右。这种情况的判断也很简单,就是满足 i 和 i+1 括号种类相同的位置最多有两个。

int T; int n,m; char s[N]; int main() { T = read(); while(T--) { scanf("%s",s+1); n = strlen(s+1); for(int i=1;i<=n;i++) { if(s[i]==')') s[i] = '('; if(s[i]==']') s[i] = '['; } int er = 0; for(int i=1;i<=n-1;i++) { if(s[i]==s[i+1]) er++; } if(er>2) cout<<"No\n"; else cout<<"Yes\n"; } return 0; }

1|4G:


过的人没A多,但我觉得这种典题反而更容易想出来。

这种两两冲突的问题很容易转换成图论,一条边连两个点,两个点只能选一个。复杂点的题目可以用2-sat,这题是普通的二分图染色。

如果有两行的同一列都是1,那么这两行必须让某一行翻转,这就是一种冲突。后来发现不能单纯记录这一种冲突,因为有的关系是要么两行都翻转,要么两行都不翻转。

这种题也好解决,只需要把每行拆成两个点,一个表示“翻转此行”,另一个表示“不翻转此行”,两个点只能选一个,因此给他们连一条线。

对于两行同一列都是1,必须翻转某一行,那就把“翻转A”和“翻转B”连,“不翻A”和“不翻B”连,表示两个点只能翻转一个。

对于两行镜像列分别为1(第i列和第m+1-i列),两行状态必须保持一致,那就把“翻转A”和“不翻B”连,“不翻A”和“翻转B”连。

如果某列(加上镜像列)超过3个1,或者最中间的列超过2个1,不合法。无法对整个图进行二分图染色,也不合法。

方案数就是2的连通块个数次方,比较经典的计数。

int T; int n,m; char s[N]; vector <int> d[N]; vector <int> e[N]; int vis[N]; int ans; int DFS(int u) { FOR() { int v = e[u][i]; if(vis[v]==vis[u]) return 0; if(vis[v]) continue; vis[v] = (vis[u]==1)?2:1; if(!DFS(v)) return 0; } return 1; } int main() { T = read(); while(T--) { n = read(); m = read(); for(int i=1;i<=m;i++) d[i].clear(); for(int i=1;i<=2*n;i++) e[i].clear(), vis[i] = 0; ans = 1; for(int i=1;i<=n;i++) { scanf("%s",s+1); for(int j=1;j<=m;j++) if(s[j]=='1') d[j].push_back(i); } if(m&1) if(d[m/2+1].size()>1) { cout<<0<<endl; continue; } bool duo = 0; for(int i=1;i<=n;i++) { e[i].push_back(i+n); e[i+n].push_back(i); } for(int i=1;i<=m/2;i++) { if(d[i].size()+d[m+1-i].size()>2) {duo = 1; break;} if(d[i].size()+d[m+1-i].size()<2) continue; if(d[i].size()==1) { int u = d[i][0], v = d[m+1-i][0]; if(u==v) continue; e[u].push_back(v+n); e[v+n].push_back(u); e[v].push_back(u+n); e[u+n].push_back(v); } else { int u,v; if(d[i].size()) u = d[i][0], v = d[i][1]; else u = d[m+1-i][0], v = d[m+1-i][1]; e[u].push_back(v); e[v].push_back(u); e[u+n].push_back(v+n); e[v+n].push_back(u+n); } } if(duo) { cout<<0<<endl; continue; } for(int i=1;i<=2*n;i++) { if(vis[i]) continue; vis[i] = 1; if(DFS(i)) (ans *= 2) %= p; else ans = 0; } cout<<ans<<endl; } return 0; }

1|5K:


先把 ai 变成 aii

将某一个区间全部变成同一个数的最优方案,就是所有数往中间凑,容易发现往中位数凑是最优的。

维护中位数的数据结构,可以用对顶堆(顾名思义,一听就懂),由于这题涉及到删除,可以用两个multiset。

由于此题的性质:如果大区间可以满足要求,那么小区间一定也满足要求,因此从左到右的每一个L,其最远位置R也是向右递增的。这就是做出此题的第二个关键点,用双指针。

R向右移动就是加入一个值,L向右移动就是删除一个值,用两个multiset一个记录较小一半,一个记录较大一半,使所有数相同的总步数为较大一半的和减去较小一半的和。复杂度O(nlogn)。

维护二顶堆时为了防止越界,可以先往左堆压入一个负无穷,右堆压入一个正无穷,由于中位数游离在两堆之外,因此需要按照总个数的奇偶分类讨论。

ll T; ll n,m,k; ll ans,a[N]; multiset <ll> s1,s2; ll zuo,you,zhong; bool jiou = 0; inline ll read() { ll sum = 0, ff = 1; char c = getchar(); while(c<'0' || c>'9') { if(c=='-') ff = -1; c = getchar(); } while(c>='0'&&c<='9') { sum = sum * 10 + c - '0'; c = getchar(); } return sum * ff; } void chushihua() { s1.clear(); s2.clear(); s1.insert(-inf); s2.insert(inf); zuo = you = zhong = 0; jiou = 0; } inline void add(ll x) { if(!jiou) { ll A = *(--s1.end()); ll B = *s2.begin(); if(A<=x && x<=B) { zhong = x; } else if(A>x) { s1.erase(s1.find(A)); s1.insert(x); zuo += x-A; zhong = A; } else if(B<x) { s2.erase(s2.find(B)); s2.insert(x); you += x-B; zhong = B; } } else { if(x>=zhong) { s1.insert(zhong); zuo += zhong; s2.insert(x); you += x; } else { s2.insert(zhong); you += zhong; s1.insert(x); zuo += x; } zhong = 0; } jiou ^= 1; } inline void del(ll x) { ll A = *(--s1.end()); ll B = *s2.begin(); if(!jiou) { if(A>=x) { s1.erase(s1.find(x)); zuo -= x; s2.erase(s2.find(B)); you -= B; zhong = B; } else { s2.erase(s2.find(x)); you -= x; s1.erase(s1.find(A)); zuo -= A; zhong = A; } } else { if(zhong==x) {} else if(x>zhong) { s2.erase(s2.find(x)); s2.insert(zhong); you += zhong-x; } else { s1.erase(s1.find(x)); s1.insert(zhong); zuo += zhong-x; } zhong = 0; } jiou ^= 1; } int main() { T = read(); while(T--) { chushihua(); n = read(); k = read(); for(ll i=1;i<=n;i++) a[i] = read()-i; a[n+1] = inf; ll now = 1; ans = 1; add(a[1]); jiou = 1; for(ll i=1;i<=n;i++) { while(you-zuo<=k) { ans = max(ans,now-i+1); add(a[++now]); } del(a[i]); } cout<<ans<<endl; } return 0; }

1|6M:


银牌计算几何题。

有两种做法,都需要极角排序。这里提供一个以O为极点,从向量OP开始逆时针排序的板子(注:只排角度不排长度):

double operator ^ (D A,D B) { return A.x*B.y - B.x*A.y; } //叉积 D O = {0,0}, P = {-1,0}; inline bool cmp(D A,D B) { //极角排序 (OP向量逆时针) if(((P-O)^(A-O))==0 && (P.x-O.x)*(A.x-O.x)>0) return 1; if(((P-O)^(B-O))==0 && (P.x-O.x)*(B.x-O.x)>0) return 0; if((((P-O)^(A-O))>0) != (((P-O)^(B-O))>0)) return ((P-O)^(A-O)) > ((P-O)^(B-O)); return ((A-O) ^ (B-O)) > 0; }

此题第一种解法是枚举凸包内部的点作为极点,排序后发现如果凸包上某一条边满足题意,需要这个小三角形内没有其他点,也就是凸包上这两个点极角排序顺序相邻。

第二种解法是枚举凸包上的边,看看内部哪些点和这条边组成的三角形中没有其他点。这是一个经典的二维偏序问题。先按第一个点排序,记录每个点的排名,保持这些排名不变再按第二个点排序。

满足题意的点特征很好推,这里不方便讲,自己画画就知道了。

第一种解法代码:

ll T; ll n,m; ll a[N]; struct D{ ll x,y; }d[N]; inline bool cmp(D A,D B) { return (A.x==B.x) ? (A.y<B.y) : (A.x<B.x); } struct D1{ ll x,y,id; }d1[N]; D1 O,P; D1 operator - (D1 A,D1 B) { return {A.x-B.x,A.y-B.y,0}; } ll operator ^ (D1 A,D1 B) { return A.x*B.y - B.x*A.y; } inline bool cmp_vec(D1 A,D1 B) { if(((P-O)^(A-O))==0 && (P.x-O.x)*(A.x-O.x)>0) return 1; if(((P-O)^(B-O))==0 && (P.x-O.x)*(B.x-O.x)>0) return 0; if((((P-O)^(A-O))>0) != (((P-O)^(B-O))>0)) return ((P-O)^(A-O)) > ((P-O)^(B-O)); return ((A-O) ^ (B-O)) > 0; } ll st[N],cnt; ll vis[N]; ll cha(D aa,D bb,D cc) { D A = {bb.x-aa.x,bb.y-aa.y}; D B = {cc.x-bb.x,cc.y-bb.y}; return A.x*B.y - A.y*B.x; } void TUBAO() { st[1] = 1; st[2] = 2; cnt = 2; for(ll i=3;i<=n;i++) { while(cnt>1 && cha(d[st[cnt-1]], d[st[cnt]], d[i])<=0) cnt--; st[++cnt] = i; } st[++cnt] = n-1; for(ll i=n-2;i>=1;i--) { while(cnt>1 && cha(d[st[cnt-1]], d[st[cnt]], d[i])<=0) cnt--; st[++cnt] = i; } --cnt; } int main() { n = read(); for(ll i=1;i<=n;i++) { d[i].x = read(); d[i].y = read(); } sort(d+1,d+n+1,cmp); TUBAO(); for(ll i=1;i<=cnt;i++) vis[st[i]] = 1; ll ans = 1; ll tot = 0; for(ll u=1;u<=n;u++) { if(vis[u]) continue; tot = 0; for(int i=1;i<=n;i++) if(i!=u) d1[++tot] = {d[i].x,d[i].y,vis[i]}; O = {d[u].x,d[u].y,0}; P = {O.x-1,O.y,0}; sort(d1+1,d1+tot+1,cmp_vec); if(d1[1].id && d1[tot].id) ans++; for(int i=1;i<tot;i++) if(d1[i].id && d1[i+1].id) ans++; } cout<<ans; return 0; }

第二种解法代码(相同函数省去):

ll T; ll n,m; ll a[N]; struct D{ ll x,y; }d[N]; ll st[N],cnt; ll vis[N]; ll hou[N]; int main() { n = read(); for(ll i=1;i<=n;i++) { d[i].x = read(); d[i].y = read(); } sort(d+1,d+n+1,cmp); TUBAO(); for(ll i=1;i<=cnt;i++) vis[st[i]] = 1; ll ans = 1; ll tot = 0; for(ll j=1;j<=n;j++) if(!vis[j]) d1[++tot] = {d[j].x,d[j].y,0}; if(tot==0) { cout<<ans; return 0; } for(ll i=1;i<=cnt;i++) { O = {d[st[i]].x,d[st[i]].y,0}; P = {d[st[i+1]].x,d[st[i+1]].y,0}; sort(d1+1,d1+tot+1,cmp_vec); for(ll j=1;j<=tot;j++) d1[j].id = j; O = {d[st[i+1]].x,d[st[i+1]].y,0}; P = {d[st[i]].x,d[st[i]].y,0}; sort(d1+1,d1+tot+1,cmp_vec); hou[tot+1] = tot+1; for(ll j=tot;j>=1;j--) hou[j] = min(hou[j+1],d1[j].id); for(ll j=1;j<=tot;j++) { if(hou[j+1]>d1[j].id) ans++; } } cout<<ans; return 0; }

1|7E:


1e5的数据,n方的二分图匹配求法都求不出来,发现边数较少,所以只能是网络流了。

这题dinic的复杂度不太会证,估计这题很多队没过的原因也是因为超时,CF的评测机dinic是可以跑过的,所以就只讲个思路当做参考了。

考虑跑完二分图匹配后残余网络的意义:从源点出发已经无法找到一条增广路到底汇点,因为所有的路已经被割了。

我们只需加一条边,使得这张残余图产生一条增广路即可。

正解:DFS查找从源点出发可以到达多少点(而且是二分图左边的点),以及有多少点可以到达汇点(而且是二分图右边的点),乘起来就是答案,思路还是比较简单的,稍微知道残余网络长什么样就能想出来(虽然这题想出来不代表评测机跑得过)。

这份代码勉强跑得进3s:

int T; int n,m,s,t; int ans[2]; int vis[N],dep[N]; int head[N],cur[N],cnt=1; struct E{ int to,nxt,cap; }e[qwq]; queue <int> q; void chushihua() { for(int i=s;i<=t;i++) head[i] = cur[i] = 0; cnt = 1; ans[0] = ans[1] = 0; } inline void add(int u,int v,int w) { e[++cnt] = {v,head[u],w}; head[u] = cnt; e[++cnt] = {u,head[v],0}; head[v] = cnt; } bool SPFA() { for(int i=s;i<=t;i++) dep[i] = inf, vis[i] = 0, cur[i] = head[i]; q.push(s); dep[s] = 0; while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(int i=head[u]; i; i=e[i].nxt) { int v = e[i].to; if(dep[v]>dep[u]+1 && e[i].cap) { dep[v]=dep[u]+1; if(vis[v]) continue; q.push(v); vis[v] = 1; } } } return dep[t] != inf; } int DFS(int u,int flow) { int res = 0, f; if(u==t || !flow) return flow; for(int i=cur[u]; i; i=e[i].nxt) { cur[u] = i; int v = e[i].to; if(e[i].cap && (dep[v]==dep[u]+1)) { f = DFS(v,min(flow-res,e[i].cap)); if(f) { res += f; e[i].cap -= f; e[i^1].cap += f; if(res==flow) break; } } } return res; } void DFS1(int u,int cl) { ans[cl] += cl?(u<=n):(u>n); vis[u] = 1; for(int i=head[u]; i; i=e[i].nxt) { int v = e[i].to; if(vis[v] || e[i].cap!=cl) continue; DFS1(v,cl); } } int main() { int x,y; T = read(); while(T--) { chushihua(); n = read(); m = read(); s = 0; t = 2*n+1; for(int i=1;i<=n;i++) add(s,i,1), add(i+n,t,1); for(int i=1;i<=m;i++) { x = read(); y = read(); add(x,y+n,1); } while(SPFA()) DFS(s,inf); for(int i=s;i<=t;i++) vis[i] = 0; DFS1(s,1); DFS1(t,0); cout<<(ll)(ans[0]-1)*(ll)(ans[1]-1)<<endl; } return 0; }

1|8B:


树形背包,但是人尽皆知是n^2,怎么优化。

根号分类讨论:

对于k小于根号n的情况,直接树形背包跑,时空复杂度均为 O(nk):上限为k的树形背包复杂度证明

对于k大于根号n的情况,我们思考会发现合法的情况并不多,这棵树切割的次数也非常少,我们还是用同样的转移方程,但是空间上用unordered_map来代替第二维,只记录方案数不为0的情况。

这样的情况总共有多少种,我们设大小为siz的子树里切了i个大小为k的块,那么根据题意可以推出:剩余的块大小一定为 (sizik)mod(k+1),因此一个 i 对应一个剩余块儿状态,每棵子树最多有根号个状态,和 k 小于根号 n 时的理论复杂度是一样的。树为一条链时复杂度拉满。

但是由于第二种情况用了unordered_map,为了平衡复杂度,我让根号的取值更大一些,让第一种情况充分跑满时间和空间(我是把根号值设到了660)。稍微改一下就卡过去了。

第二种情况代码的细节需要再多说几句:

1:因为我们只需要记录答案不为0的状态,所以出现答案为0的访问我们要立即删除,否则会越滚越多(即使没有赋值,只访问也是会往map里加入键值对的)。

2:STL比较吃内存,记得用完垃圾及时回收,map.clear()即可。

int T; int n,K; int f[N][666],siz[N],g[666]; unordered_map <int,int> F[N],G; vector <int> e[N]; inline int read() { int sum = 0, ff = 1; char c = getchar(); while(c<'0' || c>'9') { if(c=='-') ff = -1; c = getchar(); } while(c>='0'&&c<='9') { sum = sum * 10 + c - '0'; c = getchar(); } return sum * ff; } void chushihua() { for(int i=1;i<=n;i++) e[i].clear(); int sq = 660; if(K<=sq) for(int i=1;i<=n;i++) for(int j=0;j<=K+1;j++) f[i][j] = 0; else F[1].clear(); } void DFS1(int u,int fa) { siz[u] = 1; f[u][1] = 1; FOR() { int v = e[u][i]; if(v==fa) continue; DFS1(v,u); for(int j=0;j<=K+1;j++) g[j] = 0; // 由于这个背包是必须强制选,所以之前的状态需要删除,我用临时数组g来实现转移。 for(int j=0;j<=min(K,siz[v]);j++) { for(int k=min(K+1-j,siz[u]);k>=1;k--) (g[j+k] += (ll)((ll)f[v][j] * (ll)f[u][k]) %p) %= p; } for(int j=0;j<=K+1;j++) f[u][j] = g[j]; siz[u] += siz[v]; } f[u][0] = (f[u][K] + f[u][K+1]) %p; } void DFS2(int u,int fa) { siz[u] = 1; F[u][1] = 1; FOR() { int v = e[u][i]; if(v==fa) continue; DFS2(v,u); G.clear(); for(auto j : F[v]) { for(auto k : F[u]) { if(j.first+k.first>K+1) continue; (G[j.first+k.first] += (ll)((ll)j.second * (ll)k.second) %p) %= p; } } F[u].clear(); for(auto j : G) F[u][j.first] = j.second; siz[u] += siz[v]; } F[u][0] = (F[u][K] + F[u][K+1]) %p; if(F[u][K]==0) F[u].erase(K); if(F[u][K+1]==0) F[u].erase(K+1); // 这三个点没有赋值,但是访问了,需要判断下是否是空键值对。 if(F[u][0]==0) F[u].erase(0); for(int v : e[u]) if(v!=fa) F[v].clear(); } int main() { int x,y; T = read(); while(T--) { chushihua(); n = read(); K = read(); int sq = 660; for(int i=1;i<n;i++) { x = read(); y = read(); e[x].push_back(y); e[y].push_back(x); } if(K<=sq) { DFS1(1,1); cout<<(f[1][0]%p+p)%p<<endl; } else { DFS2(1,1); cout<<(F[1][0]%p+p)%p<<endl; } } return 0; }

2|0后记:充满遗憾的散伙场


和我组队的是两位学长,有一位即将毕业了,所以今年是我们队伍最后一年,明年需要重组。

UESTC_404,我们调侃自己是老银牌队,因为之前所有的比赛都是银牌,银牌首、中、尾都拿过。但这最后一场比赛,却是以铜牌告终。

赛季前,我们学校发生了闻名贴吧的 “电子科技大学22只雄性事件”,所以我们中文名选用了 “UESTC_三只雄性”。

热身赛做完四道题之后,我们发现我们队正好在菜狗上面,非常兴奋,赶紧拍照留念,虽然后面我们两队中间又夹了几个队,不过有幸拍到了那一刻。我们觉得是个好兆头。

正式赛的第一个小时我们顺利做完了 D G I 三道题,A题稍微卡了下也在半小时之后做出来了,殊不知这就是整场所有的戏份了。

之后我看了E题,随口提了句 “跑完网络流在残余网络上搞搞试试?”,但是发现基本没人做就放弃了,先看 K 和 M。

我和队友 K 题的思路有分歧,我是想先差分,然后题意转化为左右移动小石子使得区间全为0,队友觉得应该先二分,然后数据结构维护下。后来想到对顶堆可以维护中位数,我就上去写,我的脑子就是从这时候开始混沌的。

二分答案(序列长度),再套个STL,本来就是俩log,我一直觉得不放心。一开始我选的是priority_queue,因为涉及到删除,我用一个数组来表示每个数的剩余数量,发现很难写,调了很久样例都没过,浪费了好多时间,队友说换成set不就好写了,对啊,我就赶紧又写了份multiset。

这段时间是比较难熬的,因为两个log自己都觉得过不去,却还是硬着头皮写完了,(我们一直在想怎么优化掉STL的这个log来着),期间唯一欣慰点的是队友会做 M 了。

一交,果然TLE了,悬着的心终于死了。

赶紧换队友写M,这时候已经知道自己与金牌无缘了,想着这场能过六题就知足了。

队友改了很久的排序顺序(应该是二维偏序那里,“正着不对?换倒着试试”),终于过样例了,然后一交,WA。

然后我们队就死气沉沉了,我还一直在想 K 题怎么避免用STL。终于队友发现根本不用二分,用双指针就行了,匆匆忙改了改,交上去变成了RE,这下给整不会了。

我一直以为是我们的双指针越界的问题,因为数组开的够大,而且set里有无穷大,应该不会是STL越界的问题。直到前几天补题(揭伤疤的感觉),才知道multiset在erase时,如果是迭代器,则只会删除一个值,如果是数值,会把所有位置全删掉。我们这题就是因为删的数多了所以RE掉了。

也不能怪时运,其实是自己STL基础没打好,唉。

至于M题,其实到现在还不知道WA的原因。

我们队就一直被这两题卡着卡到比赛结束,最恶心的一场。

我们学校的另外两个队,WiFi和花火,都是8题金牌(WiFi其实也是崩了,只做了8题)。我们却只有4题,4题首位,甚至领先第二80分钟。

大一刚打ICPC时,我一直期望的是学长带飞自己,所以一直是漫不经心。这场打完之后,我突然觉得作为学弟更应该负起责任,因为明年,我还有机会参加比赛,但学长的成绩就只能止步于此了。

这场ICPC成为了我们几个人参赛以来最大的遗憾,因为要散伙了,难免会有些气愤,感到时运不济之类的(比如回来的飞机上我突然觉得E怎么这么简单,之前做过好几道处理残余网络的题)。

虽然今年与EC无缘,但是我才大二,明年还有机会。需要有把自己作为队伍主力的心态,即使不是主力,也要以此为目标去努力,以后才能至少不像这场散伙赛一样让人感到遗憾。


__EOF__

本文作者枫叶晴
本文链接https://www.cnblogs.com/maple276/p/18005460.html
关于博主:菜菜菜
版权声明:呃呃呃
声援博主:呐呐呐
posted @   maple276  阅读(3657)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示