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  阅读(629)  评论(0编辑  收藏  举报