首页 > 其他分享 >CF627F Island Puzzle.

CF627F Island Puzzle.

时间:2022-09-23 20:00:50浏览次数:53  
标签:cnt ++ Island Puzzle fat res CF627F now ll

容易观察到一次操作是将 \(0\) 移动到一个相邻的节点上,而且操作可逆转。

所以对于不加边的情况方案是唯一的,直接模拟一下看看是不是相等的就好。

对于加一条边来说,我们先将 \(0\) 移动到目标位置,观察一下这种状态下他的答案长什么样子。

因为操作是可逆的,所以对于 \(0\) 出去再回来的话,他能改变的只有在加一条边形成的环上的点,而改变的方式则是先拿出一个点来,剩下的点转一下,再把拿出来的这个点塞回去。

那么我们可以找到需要改变的这个环,如果需要改变的点形不成一条路径,那么答案为 \(-1\)。

形成环的话我们找到这个环一开始被拿出来的那个点,这个时候路径就确定了,求最优解只需要把和开始时 \(0\) 向终点移动时的路径相反的部分减掉就可以了,复杂度 \(O(n)\)。

代码:

#include<bits/stdc++.h> 
#define N 201001
#define MAX 2005
using namespace std;
typedef long long ll;
typedef double db;
const ll inf=1e18,mod=1e9+7;
inline void read(ll &ret)
{
	ret=0;char c=getchar();bool pd=false;
	while(!isdigit(c)){pd|=c=='-';c=getchar();}
	while(isdigit(c)){ret=(ret<<1)+(ret<<3)+(c&15);c=getchar();}
	ret=pd?-ret:ret;
	return;
}
ll n,a[N],b[N],x,y,pos[N],p,s,t;
bool f[N];
vector<ll>v[N];
ll fat[N];
ll dep[N];
inline void dfs(ll ver,ll fa)
{
	fat[ver]=fa;
	for(int i=0;i<v[ver].size();i++)
	{
		ll to=v[ver][i];
		if(to==fa)
			continue;
		dep[to]=dep[ver]+1;
		dfs(to,ver);
	}
	return;
}
ll tmp[N];
ll lis[N],tot;
inline bool cmp(ll x,ll y)
{
	return dep[x]>dep[y];
}
bool vis[N];
ll tp[N];
vector<ll>g;
ll h[N],cnt;
inline ll calc1()
{
	cnt=0;
	ll res=0;
	if(g.size()==1)
	{
		ll now=g[0];
		while(now!=p)
		{
			h[cnt++]=now;
			if(!f[now])
				res++;
			else
				res--;
			now=fat[now];
		}
		res++;
		h[cnt++]=p;
		reverse(h,h+cnt);
		for(int i=0;i<cnt;i++)
			pos[b[h[i]]]=i;
		set<ll>dt;
		for(int i=1;i<cnt;i++)
		{
			ll d=0;
			if(pos[tmp[h[i]]]<i)
				d=i-pos[tmp[h[i]]];
			else
				d=i+cnt-1-pos[tmp[h[i]]];
			dt.insert(d);
		}
		if(dt.size()>1)
		{
			puts("-1");
			exit(0);
		}
		ll d=*dt.begin();
		return res+(d-1)*cnt;
	}
	else
	{
		ll now=g[0];
		while(now!=p)
		{
			h[cnt++]=now;
			if(!f[now])
				res++;
			else
				res--;
			now=fat[now];
		}
		h[cnt++]=p;
		reverse(h,h+cnt);
		res++;
		now=g[1];
		while(now!=p)
		{
			h[cnt++]=now;
			res++;
			now=fat[now];
		}
		for(int i=0;i<cnt;i++)
			pos[b[h[i]]]=i;
		set<ll>dt;
		for(int i=1;i<cnt;i++)
		{
			ll d=0;
			if(pos[tmp[h[i]]]<i)
				d=i-pos[tmp[h[i]]];
			else
				d=i+cnt-1-pos[tmp[h[i]]];
			dt.insert(d);
		}
		if(dt.size()>1)
		{
			puts("-1");
			exit(0);
		}
		ll d=*dt.begin();
		return res+(d-1)*cnt;
	}
}
inline ll calc2()
{
	cnt=0;
	ll res=0;
	if(g.size()==1)
	{
		ll now=g[0];
		h[cnt++]=p;
		res++;
		while(now!=p)
		{
			h[cnt++]=now;
			res++;
			now=fat[now];
		}
		for(int i=0;i<cnt;i++)
			pos[b[h[i]]]=i;
		set<ll>dt;
		for(int i=1;i<cnt;i++)
		{
			ll d=0;
			if(pos[tmp[h[i]]]<i)
				d=i-pos[tmp[h[i]]];
			else
				d=i+cnt-1-pos[tmp[h[i]]];
			dt.insert(d);
		}
		if(dt.size()>1)
		{
			puts("-1");
			exit(0);
		}
		ll d=*dt.begin();
		return res+(d-1)*cnt;
	}
	else
	{
		ll now=g[1];
		while(now!=p)
		{
			h[cnt++]=now;
			if(!f[now])
				res++;
			else
				res--;
			now=fat[now];
		}
		h[cnt++]=p;
		reverse(h,h+cnt);
		res++;
		now=g[0];
		while(now!=p)
		{
			h[cnt++]=now;
			res++;
			now=fat[now];
		}
		for(int i=0;i<cnt;i++)
			pos[b[h[i]]]=i;
		set<ll>dt;
		for(int i=1;i<cnt;i++)
		{
			ll d=0;
			if(pos[tmp[h[i]]]<i)
				d=i-pos[tmp[h[i]]];
			else
				d=i+cnt-1-pos[tmp[h[i]]];
			dt.insert(d);
		}
		if(dt.size()>1)
		{
			puts("-1");
			exit(0);
		}
		ll d=*dt.begin();
		return res+(d-1)*cnt;
	}
}
signed main()
{
	read(n);
	for(int i=1;i<=n;i++)
	{
		read(a[i]);
		if(!a[i])
			s=i;
		tmp[i]=a[i];
	}
	for(int i=1;i<=n;i++)
	{
		read(b[i]);
		if(!b[i])
			t=i;
	}
	for(int i=1;i<n;i++)
	{
		read(x);
		read(y);
		v[x].push_back(y);
		v[y].push_back(x);
	}
	dfs(t,0);
	ll now=s;
	while(fat[now])
		swap(tmp[fat[now]],tmp[now]),f[now]=true,now=fat[now];
	bool flag=true;
	for(int i=1;i<=n;i++)
		flag&=tmp[i]==b[i];
	if(flag)
	{
		printf("0 %lld\n",dep[s]);
		exit(0);
	}
	for(int i=1;i<=n;i++)
	{
		if(tmp[i]!=b[i])
			lis[++tot]=i;
	}
	sort(lis+1,lis+tot+1,cmp);
	set<ll>st;
	st.clear();
	ll num=0;
	for(int i=1;i<=tot;i++)
	{
		if(vis[lis[i]])
			continue;
		g.push_back(lis[i]);
		num++;
		ll now=lis[i];
		vector<ll>c;
		c.clear();
		while(now&&!vis[now]&&tmp[now]!=b[now])
			c.push_back(now),vis[now]=true,now=fat[now];
		for(auto x:c)
			tp[x]=now;
		st.insert(now);
	}
	if(num>2||st.size()>1)
	{
		puts("-1");
		exit(0);
	}
	p=*st.begin();
	if(num==1)
		x=p,y=lis[1];
	else
		x=g[0],y=g[1];
	ll ans=dep[s];
	now=p;
	while(fat[now])
	{
		if(!f[now])
			ans++;
		else
			ans--;
		now=fat[now];
	}
	ans+=dep[p];
	ans+=min(calc1(),calc2());
	printf("%lld %lld %lld\n",min(x,y),max(x,y),ans);
	exit(0);
}

标签:cnt,++,Island,Puzzle,fat,res,CF627F,now,ll
From: https://www.cnblogs.com/CelticBlog/p/16724059.html

相关文章

  • vue-puzzle-vcode与vue-drag-verify纯前端的拼图人机验证、右滑拼图验证
    转载作品!以获取原作者允许,原文地址,感觉写的比较全面,也比较实用,大家可以去看看原文章;纯前端的拼图人机验证、右滑拼图验证1、vue-puzzle-vcodegithub地址:https://github......
  • CodeForces-1472F New Year's Puzzle
    NewYear'sPuzzle模拟如果尝试从左到右放,就会发现其实放的基本是唯一的,因此考虑直接模拟就好了针对当前列,分成三种状态:状态\(0\):上下都不能放状态\(1\):下面不......
  • CF713D Animals and Puzzle
    题意:\(n*m\)矩阵,每个点为0或1,每次给定一个矩形区间,问最大能够画出边长为多少的正方形保证正方形内的每一个数都是1.首先是动规。f[i][j]表示以(i,j)点位左下角的正方......