NOIP2020 退役记

NOIP2020 退役记

把原来写的东西全删了。毕竟留下了不少遗憾,也让我自己失望了吧。

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\),可以放心写,不怎么卡常数。

#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;
}
posted @ 2020-12-05 20:26  Owen_codeisking  阅读(716)  评论(0)    收藏  举报