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\) 一定有一個串符合條件,用了 \(C\in (6m,7m)\) 次操作。

上界大概是 \(O(F(n)\times 7m)\)\(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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章