Exact Neighbours (Medium)

最爱丁珰發表於2024-07-07

官解的方法二就是這篇部落格(注意要先將\(a\)從小到大排序),補充一下,部落格中說當\(a_j-j+1<0\)時,我們就找第\(j-a_j\)列的那個房子即可

我在做的時候,也想到了逐個構造的方法,然而我在構造新的一列時,卻總是想讓這一列的房子與前一列的房子來配對,事實證明,我們構造的時候不要拘泥於數學歸納法,可以從強數學歸納的思想出發,去找前面所有構造好了的房子

官解的方法一沒有看懂英文是啥意思

我的方法與上述兩種方法都不同:

顯然\(1\)號房子是最特殊的,所以我們將其放在\((1,1)\),然後我們採用逐個構造法,發現如果存在兩個\(a\)相同的房子就不太好構造,於是我們將相同的房子兩兩配對,並且從最後一列依次往前面放(顯然合法),最後剩下的還沒有配對的房子的\(a\)都不同,於是嘗試將其與\(1\)號房子配對,注意此時第二列的距離可以放\(1\)\(n\),第三列的距離可以放\(2\)\(n\),依次類推,於是我們將剩下的房子排序,顯然從小到大依次放置就合法;具體見以下程式碼,非常easy

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+10;
const ll mod=998244353;
int n;
bool mark[N];
struct node
{
	int id,a;//id表示房子的編號,a如題目所述 
}t[N];
struct Node
{
	int x,y,to;//(x,y)是房子的座標,to是與其配對的房子編號 
}ans[N];
bool cmp(node i,node j)
{
	if(i.a==j.a) return i.id<j.id;
	return i.a<j.a;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) 
	{
		t[i].id=i;
		scanf("%d",&t[i].a);
	}
	sort(t+1,t+n+1,cmp);
	for(int i=2,last=n;i<=n;i++)//last表示最後的還沒有放置房子的列,我們從後往前依次放置 
	if(t[i].a==0)//注意0的單獨放置一列就好了 
	{
		ans[t[i].id].x=last--,ans[t[i].id].y=1;
		ans[t[i].id].to=t[i].id;
		mark[i]=1;
	}
	else if(t[i].a==t[i-1].a)
	{
		ans[t[i].id].x=last--,ans[t[i].id].y=1;
		ans[t[i-1].id].x=last--,ans[t[i-1].id].y=t[i].a;
		ans[t[i].id].to=t[i-1].id,ans[t[i-1].id].to=t[i].id;
		mark[i]=mark[i-1]=1;
		i++;
	}
	ans[1].x=ans[1].y=ans[1].to=1;
	for(int i=2,last=2;i<=n;i++)
	if(!mark[i])
	{
		ans[t[i].id].x=last++,ans[t[i].id].y=t[i].a-ans[t[i].id].x+2;
		ans[t[i].id].to=1;
	}
	puts("YES");
	for(int i=1;i<=n;i++)
	printf("%d %d\n",ans[i].x,ans[i].y);
	for(int i=1;i<=n;i++) printf("%d ",ans[i].to);
	return 0;
}

相關文章