NOIP2020 退役记

Owen_codeisking

2020-12-05 20:32:43

Personal

把原来写的东西全删了。毕竟留下了不少遗憾,也让我自己失望了吧。 12:30 想到 T3 怎么做,写完后发现第二个样例过不去,也就爆零了。 晚上回家理顺了一遍思路,写了半个小时不到就写完并在 oitiku 上 AC 了。我刷了不少 AGC 和 CF 的构造题,原本只是准备省选和 NOI 写的,结果 NOIP 考到了。我以为我能暴切 T3 考到省队线,结果被 T3 送退役了。 估分 $80\sim 100+84\sim 100+0+60\sim 80=224\sim 280$。不过应该省选还是会去的,但是翻盘的可能性不大了。 不过我也努力过了,这次的失误也是我想题较慢的缘故。若是把这道 T3 放到省选或 NOI 上,我感觉自己能现场写出来的。太遗憾了,实在是太遗憾了。 要是 T3 一点都不会做该多好,这样我就可以安心退役了。我真的心有不甘啊啊啊啊啊啊。 唉,在绝望中给人希望是一件多么残酷的事情。 T3 做法: 考虑分治,将颜色编号 $\le mid$ 和 $>mid$ 分为两个集合。这样问题转化为只用若干个长度为 $m$ 的 $01$ 串,将要求每个串全部 $0/1$。 接着考虑两个串 $S,T$。可以知道,$cnt_{S,0/1}+cnt_{T,0/1}$ 总有一个 $\ge m$。那么,我们可以通过如下构造,得到一个串全部 $0/1$。 设空串为 $now$。取 $S,T$ 的后 $\lfloor \frac m2\rfloor$ 位,放到 $now$ 中。如果是 $0$ 放到 $S$,$1$ 放到 $T$,那么可以得到一个长为 $\lfloor \frac m2\rfloor$ 的串全部 $0/1$。若是 $S$,再将 $S$ 全部放到 $now$。此时 $S$ 为空串,$T$ 没有性质,$now$ 前 $\lfloor \frac m2\rfloor$ 位相等。此处用了 $3m$ 次操作。 对于串 $now$ 和 $T$,我们取 $now$ 的后 $\lceil \frac m2\rceil$ 位,$T$ 的后 $\lfloor \frac m2\rfloor$ 位,执行类似刚才的操作。此时 $now$ 的后 $\lceil \frac m2\rceil$ 位相等。此处用了 $2m$ 次操作。 现在讨论 $now$ 前 $\lfloor \frac m2\rfloor$ 位和后 $\lceil \frac m2\rceil$ 位是否相等。若相等,那么我们已经构造了出来。否则,将 $now$ 的后 $\lceil \frac m2\rceil$ 位放到 $S$,然后对 $T$ 执行刚才的过程。如果是 $0$ 放到 $S$,$1$ 放到 $now$。这样 $S/now$ 一定有一个串符合条件,用了 $\frac 32m$ 次操作。 上界大概是 $O(F(n)\times \frac {13}{2}m)$,$F(n)=\sum (len_{rt}-1)$,$rt\in$ 长度为 $n$ 的线段树。$F(50)=237$,可以放心写,不怎么卡常数。 ```cpp #include <bits/stdc++.h> using namespace std; const int maxn=55; const int maxa=820005; int n,m,x_[maxa],y_[maxa],sz,now; vector<int> g[maxn]; inline void add(int x,int y) { x_[++sz]=x,y_[sz]=y; g[y].push_back(g[x].back()); g[x].pop_back(); } void solve(int l,int r,vector<int> &id) { if(id.size()==1) return; int mid=(l+r)>>1; vector<int> A,B; A.clear(),B.clear(); while(!id.empty()) { int s=id.back(); id.pop_back(); int t=id.back(); id.pop_back(); // s, t -> now for(int i=0;i<m/2;i++) add(s,now),add(t,now); int pa=0,pb=0; for(int i=0;i<g[now].size();i++) if(g[now][i]<=mid) pa++; else pb++; int op1=(pa>=m/2)?0:1; while(!g[now].empty()) { if(((op1==0 && g[now].back()<=mid) || (op1==1 && g[now].back()>mid)) && g[s].size()<m) add(now,s); else add(now,t); } for(int i=0;i<m;i++) add(s,now); for(int i=0;i<m/2;i++) add(t,s); for(int i=0;i<(m+1)/2;i++) add(now,s); int qa=0,qb=0; for(int i=0;i<g[s].size();i++) if(g[s][i]<=mid) qa++; else qb++; int op2=(qa>=(m+1)/2)?0:1; while(!g[s].empty()) { if(((op2==0 && g[s].back()<=mid) || (op2==1 && g[s].back()>mid)) && g[now].size()<m) add(s,now); else add(s,t); } if((g[now][0]<=mid)==(g[now].back()<=mid)) { if(g[now].back()<=mid) A.push_back(now); else B.push_back(now); if(id.empty()) { if(g[t].back()<=mid) A.push_back(t); else B.push_back(t); } else id.push_back(t); now=s; } else { // op1 -> now, op2 -> s for(int i=0;i<(m+1)/2;i++) add(now,s); int x=0,y=0; for(int i=0;i<g[t].size();i++) if(g[t][i]<=mid) x++; else y++; if(op2==0) { if(x+g[s].size()>=m) { while(!g[t].empty()) { if(g[t].back()<=mid && g[s].size()<m) add(t,s); else add(t,now); } A.push_back(s); if(id.empty()) { if(g[now].back()<=mid) A.push_back(now); else B.push_back(now); } else id.push_back(now); now=t; } else { while(!g[t].empty()) { if(g[t].back()>mid && g[now].size()<m) add(t,now); else add(t,s); } B.push_back(now); if(id.empty()) { if(g[s].back()<=mid) A.push_back(s); else B.push_back(s); } else id.push_back(s); now=t; } } else { if(y+g[s].size()>=m) { while(!g[t].empty()) { if(g[t].back()>mid && g[s].size()<m) add(t,s); else add(t,now); } B.push_back(s); if(id.empty()) { if(g[now].back()<=mid) A.push_back(now); else B.push_back(now); } else id.push_back(now); now=t; } else { while(!g[t].empty()) { if(g[t].back()<=mid && g[now].size()<m) add(t,now); else add(t,s); } A.push_back(now); if(id.empty()) { if(g[s].back()<=mid) A.push_back(s); else B.push_back(s); } else id.push_back(s); now=t; } } } } solve(l,mid,A),solve(mid+1,r,B); } int main() { freopen("ball.in","r",stdin); freopen("ball.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { int x; scanf("%d",&x); g[i].push_back(x); } vector<int> id; id.clear(); for(int i=1;i<=n;i++) id.push_back(i); now=n+1,solve(1,n,id); printf("%d\n",sz); for(int i=1;i<=sz;i++) printf("%d %d\n",x_[i],y_[i]); return 0; } ```