【UOJ #153】【UR #10】世界线

Description

给出一张二分图,左边点编号为1~n,右边为 n + 1 到 2 n {n+1}到{2n} n+12n
这张图满足以下特性:每个点的度数都恰好是1(左边每个点连出去一条,右边每个点被连一条,边为双向)
也就是这张图的连边方案可以用一个长度排列为n的排列描述(每个左边连向右边哪一个),

现在你只知道这张图有2n个点却不知道连边方案,但你可以通过以下流程询问交互库:

第一轮:
阶段1. addedge(x,y):交互库会在左边两点x,y之间连一条无向边;本函数可以执行多次
阶段2. query(x,y):交互库会回答右边两点x,y之间的连通性;本函数可以执行多次
注意:在阶段1是不能执行query(x,y)函数,阶段2不能执行 addedge(x,y)函数
也就是一次性连完,一次性问完
第二轮:(图已被恢复至原二分图)
阶段1. addedge(x,y):交互库会在左边两点x,y之间连一条无向边;本函数可以执行多次
阶段2. query(x,y):交互库会回答右边两点x,y之间的连通性;本函数可以执行多次
注意:同样在阶段1是不能执行query(x,y)函数,阶段2不能执行 addedge(x,y)函数

你必须在第二轮结束后输出答案,

n ≤ 10000 n\leq10000 n10000
总的连边/询问次数不得超过 2 ∗ 1 0 6 2*10^6 2106


Solution

显然的可以发现,对弈每次询问,我们可以把右边的点分成几个联通块,
为了让右边查询出的联通块和左边我们连出的联通块对应,我只能用过联通块中点的个数来区分,

那么题目就变成了:
我们构造集合集 S i S_i Si,使得集合之间没有交集,所有集合的并集为全集,且集合的大小两两不同,
同样的方法构造集合集 T i T_i Ti
构造的两个集合集需要满足,对于任意a,满足存在 S i ∩ T j = { a } S_i\cap T_j=\{a\} SiTj={a}(交集只有这一个)

显然的,当n满足存在m使得 n = ( m + 1 ) m 2 n=\frac{(m+1)m}{2} n=2(m+1)m,一定有解,
以n=10为例:
S 1 = { 1 } S_1=\{1\} S1={1}
S 2 = { 2 , 3 } S_2=\{2,3\} S2={2,3}
S 3 = { 4 , 5 , 6 } S_3=\{4,5,6\} S3={4,5,6}
S 4 = { 7 , 8 , 9 , 10 } S_4=\{7,8,9,10\} S4={7,8,9,10}
T 1 = { 10 } T_1=\{10\} T1={10}
T 2 = { 9 , 6 } T_2=\{9,6\} T2={9,6}
T 3 = { 8 , 5 , 3 } T_3=\{8,5,3\} T3={8,5,3}
T 4 = { 7 , 4 , 2 , 1 } T_4=\{7,4,2,1\} T4={7,4,2,1}

这样既可以出唯一解了,

那么对于不满足条件的n怎么办呢?
也可以用同样的方法,先不考虑联通块大小相同所带来的无法一一对应问题,
具体流程是:我们先按上面的方法分好S集,使得相邻 S i S_i Si集合大小差不超过1,
以n=8为例:
S 1 = { 1 } S_1=\{1\} S1={1}
S 2 = { 2 , 3 } S_2=\{2,3\} S2={2,3}
S 3 = { 4 , 5 } S_3=\{4,5\} S3={4,5}
S 4 = { 6 , 7 , 8 } S_4=\{6,7,8\} S4={6,7,8}
接下来,集合T的构造对于所有i满足 ∣ S i ∣ = ∣ T i ∣ |S_i|=|T_i| Si=Ti
我们从T的最后一个开始构造,假设 T i T_i Ti需要放入a个元素,那么我们就从S中,可选元素个数最大的前a个中各挑出一个来组成 T i T_i Ti
T 1 = { 1 } T_1=\{1\} T1={1}
T 2 = { 6 , 2 } T_2=\{6,2\} T2={6,2}
T 3 = { 7 , 4 } T_3=\{7,4\} T3={7,4}
T 4 = { 8 , 5 , 3 } T_4=\{8,5,3\} T4={8,5,3}

加上个表帮助理解

当前T的选择当前S的剩余
S 1 { 1 } , S 2 { 2 , 3 } , S 3 { 4 , 5 } , S 4 { 6 , 7 , 8 } S_1\{1\},S_2\{2,3\},S_3\{4,5\},S_4\{6,7,8\} S1{1},S2{2,3},S3{4,5},S4{6,7,8}
T 4 { 8 , 5 , 3 } T_4\{8,5,3\} T4{8,5,3} S 1 { 1 } , S 2 { 2 } , S 3 { 4 } , S 4 { 6 , 7 } S_1\{1\},S_2\{2\},S_3\{4\},S_4\{6,7\} S1{1},S2{2},S3{4},S4{6,7}
T 3 { 7 , 4 } T_3\{7,4\} T3{7,4} S 1 { 1 } , S 2 { 2 } , S 3 { } , S 4 { 6 } S_1\{1\},S_2\{2\},S_3\{\},S_4\{6\} S1{1},S2{2},S3{},S4{6}
T 2 { 6 , 2 } T_2\{6,2\} T2{6,2} S 1 { 1 } , S 2 { } , S 3 { } , S 4 { } S_1\{1\},S_2\{\},S_3\{\},S_4\{\} S1{1},S2{},S3{},S4{}
T 1 { 1 } T_1\{1\} T1{1} S 1 { } , S 2 { } , S 3 { } , S 4 { } S_1\{\},S_2\{\},S_3\{\},S_4\{\} S1{},S2{},S3{},S4{}

可以归纳证明,对于任意n,这种构造方法均可行,

接下来我们再来解决联通块大小相同所带来的无法一一对应问题,
显然的,当大小为1的集合出现两个时很好解决,可以直接特判掉;
设两个大小相同的集合分别为 S x , S y S_x,S_y Sx,Sy,按照定义必然 ∣ T x ∣ = ∣ T y ∣ |T_x|=|T_y| Tx=Ty
我们发现,第一轮过后,我们已经知道点1的出边是什么,记为 a 1 a_1 a1
第二轮时,我们再集合 T x T_x Tx中加入点1,那么右边与 a 1 a_1 a1相联通的联通块就一定是对应集合 T x T_x Tx的,
这样我们就成功区分出了 T x , T y T_x,T_y Tx,Ty所对应的联通块,

对于 S x , S y S_x,S_y Sx,Sy,可以发现:这两个S集合与两T集合的两两交集大小均为1,
既然我们可以通过点1区分出 T x , T y T_x,T_y Tx,Ty,那么我们在构造时就使得 T x , S y T_x,S_y Tx,Sy的交集为空,即让 T x T_x Tx少一个元素,
那么 T x T_x Tx对应的右边联通块,与 S x S_x Sx对应的右边联通块,交集大小为1,
那么 T x T_x Tx对应的右边联通块,与 S y S_y Sy对应的右边联通块,交集大小为空,

这样就完美解决了一一对应的问题,
剩下的就是简单的集合求并,
(注意:因为T有一个位置少了一个元素,所以有一个元素无法通过集合合并求出,要通过排除法求出)

Code

#include "worldline.h"

#include <cstdio>
#include <algorithm>
#include <iostream>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
using namespace std;
const int N=100500;
int read(int &n)
{
	char ch=' ';int q=0,w=1;
	for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
	if(ch=='-')w=-1,ch=getchar();
	for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
void WA()
{
	printf("WAWAWAWAWAWAWAWAWAWAWAWA\n");
	printf("WAWAWAWAWAWAWAWAWAWAWAWA\n");
	printf("WAWAWAWAWAWAWAWAWAWAWAWA\n");
	printf("WAWAWAWAWAWAWAWAWAWAWAWA\n");
	printf("WAWAWAWAWAWAWAWAWAWAWAWA\n");
	printf("WAWAWAWAWAWAWAWAWAWAWAWA\n");
	while(1);
}
int n;
int g[N],g1[N];
int bz[200][N],bz1[200][N];
int b[200][N];
int b0;
int z[N],TI;
int d[N],p[N];
void Update()
{
	fod(i,p[0]-1,1)if(b[p[i]][0]>b[p[i+1]][0])
	{
		for(int j=i;j<p[0]&&b[p[j]][0]>b[p[j+1]][0];++j)swap(p[j],p[j+1]);
	}
}
int Find(int q,int w)
{
	int i,j;
	for(i=j=1;i<=bz[q][0]&&j<=bz1[w][0];)
	{
		if(bz[q][i]==bz1[w][j])return bz[q][i];
		if(bz[q][i]<bz1[w][j])++i;
		else ++j;
	}
	return -1;
}
void doit0(int *anse)
{
	int q,w,e=0;
	fod(i,b0,1)
	{
		w=b[b0][b[b0][0]--];
		g1[w]=i;
		fod(j,b0-1,b0-i+1)addedge(b[j][b[j][0]],w),g1[b[j][b[j][0]--]]=i;
	}

	next_step();///

	++TI;
	fo(i,1,n)if(z[i]<TI)
	{
		z[i]=TI;
		d[d[0]=1]=i;
		fo(j,i+1,n)if(z[j]<TI)if(query(i,j))
		{
			z[j]=TI;
			d[++d[0]]=j;
		}
		
		bz1[d[0]][0]=d[0];
		fo(j,1,d[0])bz1[d[0]][j]=d[j];
	}
	fo(i,1,n)
	{
		anse[i]=Find(g[i],g1[i]);
	}
}
void doit1(int *anse)
{
	int q,w,e=0;
	fod(i,b0,1)
	{
		w=b[b0][b[b0][0]--];
		g1[w]=i;
		fod(j,b0-1,b0-i+1)addedge(b[j][b[j][0]],w),g1[b[j][b[j][0]--]]=i;
	}

	next_step();///

	++TI;
	fo(i,1,n)if(z[i]<TI)
	{
		z[i]=TI;
		d[d[0]=1]=i;
		fo(j,i+1,n)if(z[j]<TI)if(query(i,j))
		{
			z[j]=TI;
			d[++d[0]]=j;
		}

		if(!bz1[d[0]][0])
		{
			bz1[d[0]][0]=d[0];
			fo(j,1,d[0])bz1[d[0]][j]=d[j];
		}else
		{
			bz1[0][0]=d[0];
			fo(j,1,d[0])bz1[0][j]=d[j];
		}
	}
	if(bz1[1][1]==bz[0][1])swap(bz1[1][1],bz1[0][1]);
	else if(bz1[0][1]==bz[1][1])swap(bz[1][1],bz[0][1]);
	else if(bz1[1][1]==bz[1][1])swap(bz[1][1],bz[0][1]),swap(bz1[1][1],bz1[0][1]);
	fo(i,1,n)
	{
		anse[i]=Find(g[i],g1[i]);
	}
}

int query_permutation(int n,int anse[])
{
	::n=n;
	int q,w;
	if (n==2) return 0;
	new_round();

	fo(i,0,n+10)g[i]=g1[i]=d[i]=p[i]=0;b0=0;
	for(w=q=1;w<=n&&w+q-1<=n;w+=q,++q)
	{
		g[w]=++b0;
		fo(i,1,q-1)g[i+w]=b0,addedge(i+w,w);
	}
	fo(i,0,b0+10)fo(j,0,n+10)b[i][j]=bz[i][j]=bz1[i][j]=0;
	int LA=n-w+1;
	if(LA)
	{
		fo(i,w+1,n)addedge(w,i);
	}
	fo(i,1,n)
	{
		b[g[i]][++b[g[i]][0]]=i;
	}

	next_step();///

	++TI;
	fo(i,1,n)if(z[i]<TI)
	{
		z[i]=TI;
		d[d[0]=1]=i;
		fo(j,i+1,n)if(z[j]<TI&&query(i,j))
		{
			z[j]=TI;
			d[++d[0]]=j;
		}
		if(!bz[d[0]][0])
		{
			bz[d[0]][0]=d[0];
			fo(j,1,d[0])bz[d[0]][j]=d[j];
		}else
		{
			if(d[0]!=LA||bz[0][0])WA();
			bz[0][0]=d[0];
			fo(j,1,d[0])bz[0][j]=d[j];
		}
	}

	new_round();///
	if(LA==1)
	{
		doit1(anse);
		return 1;
	}
	if(!LA)
	{
		doit0(anse);
		return 1;
	}
	fo(i,1,b0-1)p[i]=i+1;p[0]=b0-1;
	if(LA)
	{
		++p[0];
		fod(i,b0-1,1)if(b[p[i]][0]>b[0][0])p[i+1]=p[i];
			else {p[i+1]=0;break;}
	}
	fo(i,0,p[0])d[i]=b[p[i]][0];d[p[0]+1]=-1;
	q=0;
	fo(i,1,n)g1[i]=-1;
	fod(i,d[0],1)
	{
		if(d[i]==LA&&d[i]==d[i+1])
		{
			if(p[p[0]])
			{
				w=b[p[p[0]]][b[p[p[0]]][0]--];
				addedge(1,w);
				g1[w]=0;
				fod(j,p[0]-1,p[0]-d[i]+1)if(p[j])addedge(b[p[j]][b[p[j]][0]],w),g1[b[p[j]][b[p[j]][0]--]]=0;
			}else
			{
				w=b[p[p[0]-1]][b[p[p[0]-1]][0]--];
				addedge(1,w);
				g1[w]=0;
				fod(j,p[0]-2,p[0]-d[i]+1)addedge(b[p[j]][b[p[j]][0]],w),g1[b[p[j]][b[p[j]][0]--]]=0;
			}
		}else
		{
			w=b[p[p[0]]][b[p[p[0]]][0]--];
			g1[w]=d[i];
			fod(j,p[0]-1,p[0]-d[i]+1)addedge(b[p[j]][b[p[j]][0]],w),g1[b[p[j]][b[p[j]][0]--]]=d[i];
		}
		Update();
	}

	next_step();///

	++TI;
	z[bz[1][1]]=TI;
	bz1[0][0]=0;
	fo(i,1,n)if(z[i]<TI&&query(i,bz[1][1]))
	{
		z[i]=TI;
		bz1[0][++bz1[0][0]]=i;
	}
	fo(i,1,n)if(z[i]<TI)
	{
		z[i]=TI;
		d[d[0]=1]=i;
		fo(j,i+1,n)if(z[j]<TI)if(query(i,j))
		{
			z[j]=TI;
			d[++d[0]]=j;
		}
		if(!bz1[d[0]][0])
		{
			bz1[d[0]][0]=d[0];
			fo(j,1,d[0])bz1[d[0]][j]=d[j];
		}else WA();
	}
	anse[1]=bz[1][1];
	if(LA)
	{
		if(Find(0,0)!=-1)
		{
			fo(i,1,LA)swap(bz[0][i],bz[LA][i]);
		}
	}
	++TI;
	z[anse[1]]=TI;
	fo(i,2,n)if(g1[i]>-1)
	{
		q=anse[i]=Find(g[i],g1[i]);
		z[anse[i]]=TI;
	}
	fo(i,2,n)if(g1[i]==-1)
	{
		fo(j,1,n)if(z[j]<TI)anse[i]=j;
	}
	return 1;
}
	

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
,发送类别,概率,以及物体在相机坐标系下的xyz.zip目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值