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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM