NOIP2020 退役记
把原来写的东西全删了。毕竟留下了不少遗憾,也让我自己失望了吧。
12:30 想到 T3 怎么做,写完后发现第二个样例过不去,也就爆零了。
晚上回家理顺了一遍思路,写了半个小时不到就写完并在 oitiku 上 AC 了。我刷了不少 AGC 和 CF 的构造题,原本只是准备省选和 NOI 写的,结果 NOIP 考到了。我以为我能暴切 T3 考到省队线,结果被 T3 送退役了。
估分 (80sim 100+84sim 100+0+60sim 80=224sim 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 floor) 位,放到 (now) 中。如果是 (0) 放到 (S),(1) 放到 (T),那么可以得到一个长为 (lfloor frac m2 floor) 的串全部 (0/1)。若是 (S),再将 (S) 全部放到 (now)。此时 (S) 为空串,(T) 没有性质,(now) 前 (lfloor frac m2 floor) 位相等。此处用了 (3m) 次操作。
对于串 (now) 和 (T),我们取 (now) 的后 (lceil frac m2 ceil) 位,(T) 的后 (lfloor frac m2 floor) 位,执行类似刚才的操作。此时 (now) 的后 (lceil frac m2 ceil) 位相等。此处用了 (2m) 次操作。
现在讨论 (now) 前 (lfloor frac m2 floor) 位和后 (lceil frac m2 ceil) 位是否相等。若相等,那么我们已经构造了出来。否则,将 (now) 的后 (lceil frac m2 ceil) 位放到 (S),然后对 (T) 执行刚才的过程。如果是 (0) 放到 (S),(1) 放到 (now)。这样 (S/now) 一定有一个串符合条件,用了 (frac 32m) 次操作。
上界大概是 (O(F(n) imes frac {13}{2}m)),(F(n)=sum (len_{rt}-1)),(rtin) 长度为 (n) 的线段树。(F(50)=237),可以放心写,不怎么卡常数。
#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
",sz);
for(int i=1;i<=sz;i++)
printf("%d %d
",x_[i],y_[i]);
return 0;
}