《GMOJ-Senior-3233 照片》题解

题目大意

给出 m m m个区间 [ l , r ] [l,r] [l,r] 1 ≤ l ≤ r ≤ n 1 \leq l \leq r \leq n 1lrn),所有区间合并后不一定包含 1 ∼ n 1 \sim n 1n,且每个区间内有且仅有一个点是特殊的,求 1 ∼ n 1 \sim n 1n内最多有多少个点是特殊的。若数据不合法,输出 − 1 -1 1,否则输出特殊点最多的个数。(注意:没有被区间包含的数也可以算特殊点)
对于 100 % 100\% 100%的数据, 1 ≤ n ≤ 2 × 1 0 5 1 \leq n \leq 2 \times 10^5 1n2×105

分析

这是一道动态规划( D P DP DP)题,我们可以用差分约束系统做。那么什么是差分约束系统呢?

如果一个系统由 n n n个变量和 m m m个约束条件组成,形成 m m m个形如 a i − a j ≤ k a_i-a_j \leq k aiajk的不等式( i , j ∈ [ 1 , n ] i,j \in [1,n] i,j[1,n] k k k为常数),则称其为差分约束系统( s y s t e m   o f   d i f f e r e n c e   c o n s t r a i n t s system \space of \space difference \space constraints system of difference constraints)。亦即,差分约束系统是求解关于一组变量的特殊不等式组的方法。

——引用自百度百科

简单来说,差分约束系统就是一些像 a i − a j ≤ k a_i-a_j \leq k aiajk的不等式。
对这道题,我们似乎看不出有什么形如 a i − a j ≤ k a_i-a_j \leq k aiajk的不等式。但是我们转化一下题目,设 f i f_i fi表示区间 [ 1 , i ] [1,i] [1,i]内最多有多少个特殊的点( f 0 = 0 f_0=0 f0=0),那么不等式就可以被表示出了。
对于 f i f_i fi f i − 1 f_{i-1} fi1,我们可以知道 f i ≥ f i − 1 f_i \geq f_{i-1} fifi1,变化此式可得 f i − f i − 1 ≥ 0 f_i-f_{i-1} \geq 0 fifi10 f i − 1 − f i ≤ 0 f_{i-1}-f_i \leq 0 fi1fi0。于是,第一个不等式就出来了:对于 i ∈ [ 1 , n ] i \in [1,n] i[1,n] f i − 1 − f i ≤ 0 f_{i-1}-f_i \leq 0 fi1fi0
因为对于区间 [ a , b ] [a,b] [a,b],有且仅有一个点是特殊的,所以我们可得 f b − f a − 1 = 1 f_b-f_{a-1}=1 fbfa1=1——因为如果 f b − f a − 1 < 1 f_b-f_{a-1}<1 fbfa1<1,那么区间里就没有点是特殊的了;如果 f b − f a − 1 > 1 f_b-f_{a-1}>1 fbfa1>1,那么区间里就有不止一个点是特殊的了。但 f b − f a − 1 = 1 f_b-f_{a-1}=1 fbfa1=1是等式,不是不等式,所以我们要转化一下。由 f b − f a − 1 = 1 f_b-f_{a-1}=1 fbfa1=1可得 { f b − f a − 1 ≤ 1 f b − f a − 1 ≥ 1 \left \{^{f_b-f_{a-1} \geq 1}_{f_b-f_{a-1} \leq 1} \right. {fbfa11fbfa11(两个式子要同时满足,这样一来 f b − f a − 1 = 1 f_b-f_{a-1}=1 fbfa1=1就成立了)。对于 f b − f a − 1 ≥ 1 f_b-f{a-1} \geq 1 fbfa11,变化后可得 f a − 1 − f b ≤ − 1 f_{a-1}-f_b \leq -1 fa1fb1。于是,第二、三个不等式就出来了:对于每个区间 [ a , b ] [a,b] [a,b] { f b − f a − 1 ≤ 1 f a − 1 − f b ≤ − 1 \left \{^{f_{a-1}-f_b \leq -1}_{f_b-f_{a-1} \leq 1} \right. {fbfa11fa1fb1
因为对于区间 [ a , b ] [a,b] [a,b],有且仅有一个点是特殊的,所以最后一个不等式是:对于 i i i i − 1 i-1 i1 i ∈ [ 1 , n ] i \in [1,n] i[1,n]),一定有 f i − f i − 1 ≤ 1 f_i-f_{i-1} \leq 1 fifi11
题目中样例连边后的情况如图所示:

找出不等式后,我们要怎么求出答案呢?

(差分约束系统求解时)以每个变量 a i a_i ai为结点,对于约束条件 a j − a i ≤ b k a_j-a_i \leq b_k ajaibk,连接一条有向 ( i , j ) (i,j) (i,j),边权为 b k b_k bk。我们再增加一个源点 s s s s s s与所有定点相连,边权均为 0 0 0。对这个图,以 s s s为源点运行最短路算法,最终 { d i } \{ d_i \} {di}即为一组可行解。

——引用自百度百科

简单来讲,差分约束系统求解时,对于每一个不等式 a i − a j ≤ k a_i-a_j \leq k aiajk,由 j j j i i i连一条权值为 k k k的边,最后以所有定点为源点,求最短路即可。
为什么可以这样做呢?我们观察一下 a i − a j ≤ k a_i-a_j \leq k aiajk,它移项后可以变成 a i ≤ a j + k a_i \leq a_j+k aiaj+k,这是不是很像最短路满足的 d i s j ≤ d i s i + w i , j dis_j \leq dis_i+w_{i,j} disjdisi+wi,j ( i , j ) ∈ E (i,j) \in E (i,j)E)呢?由此,我们可以想到,把这些不等式转化成有向边,把把一个量转化成点,然后用最短路求解。
根据我们的式子,可以得到连边的方案:

  1. 对于 f i − 1 − f i ≤ 0 f_{i-1}-f_i \leq 0 fi1fi0,我们由结点 i i i i − 1 i-1 i1连一条权值为 0 0 0的有向边;
  2. 对于 f a − 1 − f b ≤ − 1 f_{a-1}-f_b \leq -1 fa1fb1,我们由结点 b b b a − 1 a-1 a1连一条权值为 − 1 -1 1的有向边;
  3. 对于 f b − f a − 1 ≤ 1 f_b-f_{a-1} \leq 1 fbfa11,我们由结点 a − 1 a-1 a1 b b b连一条权值为 1 1 1的有向边;
  4. 对于 f i − f i − 1 ≤ 1 f_i-f_{i-1} \leq 1 fifi11,我们由结点 i − 1 i-1 i1 i − 1 i-1 i1连一条权值为 1 1 1的有向边。

(注意:在连边的时候,有可能会出现 i − 1 = 0 i-1=0 i1=0 a − 1 = 0 a-1=0 a1=0的情况,所以我们要新增一个结点 0 0 0
题目中样例连边后的情况如图所示:


有了边以后,我们怎么求解呢?其实,差分约束系统求解就是给某个(些)量赋予特殊的值后用最短路求出整个图的解。那么本题中也一样。我们通过 f i f_i fi的定义可以知道, f 0 = 0 f_0=0 f0=0。于是,我们就得到了求解方法:令 最短路径 0 = 0 \text{最短路径} _0=0 最短路径0=0,然后以结点 0 0 0为源点求最短路,最后输出 最短路径 n \text{最短路径} _n 最短路径n的值即可(要求 f n f_n fn的值)。又因为本题中 n n n较大,所以要用 S P F A SPFA SPFA
然而,有时候图中会有负权回路(负环),这时题目无解,于是我们要判断一下是否有负环。又由于题目数据卡 S P F A SPFA SPFA,所以我们要用堆优化 S P F A SPFA SPFA,并且在求最短路的过程中记录一下每个结点的入堆次数,如果 入堆次数 ≥ n + 1 \text{入堆次数} \geq n+1 入堆次数n+1,那么图中有负环。同时我们要卡一下时间,如果总进堆次数过了 1 0 6 10^6 106次,那么我们也认为图中有负环。
代码如下:

#include<cstdio>
void swap(int &a,int &b)//交换函数
{
	int t=a;
	a=b;
	b=t;
	return;
}
struct edge{int to/*终点*/,w/*权值*/,next/*下一条边*/;}e[1000001];//边
struct node{bool fl/*是否在堆中*/;int dis/*到结点0的距离(答案)*/,num/*进堆的次数*/,last/*最后一条连出的边*/,pos/*在堆中的位置*/;}a[200002];//点
int len;
void link(int x,int y,int w)//连边函数
{
	++len;
	e[len].to=y;
	e[len].w=w;
	e[len].next=a[x].last;
	a[x].last=len;
	return;
}
int heap[200002];//堆(heap[0]表示堆的大小)
void change(int x,int y)//交换堆中的节点
{
	swap(a[heap[x]].pos,a[heap[y]].pos);//交换a数组中记录的两个结点在堆中的位置
	swap(heap[x],heap[y]);//交换堆中的两个结点
	return;
}
void push(int x)//插入堆
{
	int p=(++heap[0]);//新增结点
	heap[p]=x;
	a[x].pos=p;
	while(p>1&&a[heap[p]].dis<a[heap[p/2]].dis)//向上调整
	{
		change(p,p/2);
		p/=2;
	}
	return;
}
void down(int x)//向下调整
{
	while(x*2<=heap[0])
	{
		int y;
		if(a[heap[x*2]].dis<a[heap[x]].dis)
		{
			y=x*2;
		}
		else
		{
			y=x;
		}
		if(x*2+1<=heap[0]&&a[heap[x*2+1]].dis<a[heap[y]].dis)
		{
			y=x*2+1;
		}
		if(y==x)
		{
			break;
		}
		change(x,y);
		x=y;
	}
	return;
}
void pop()//弹出堆顶
{
	heap[1]=heap[heap[0]--];
	down(1);
	return;
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);//读入n,m
	for(int i=0;i<=n;i++)//初始化a数组
	{
		a[i].last=-1;
		a[i].dis=2147483647;
		a[i].num=0;
		a[i].fl=0;
	}
	len=0;
	for(int i=1;i<=n;i++)
	{
		link(i-1,i,1);//对f[i]-f[i-1]<=1连边
		link(i,i-1,0);//对f[i-1]-f[i]<=0连边
	}
	for(int i=1;i<=m;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);//读入区间左右端点
		link(a-1,b,1);//对f[b]-f[a-1]<=1连边
		link(b,a-1,-1);//对f[a-1]-f[b]<=-1连边
	}
	a[0].dis=0;//初始化结点0
	heap[0]=0;//初始化堆
	push(0);//插入结点0
	a[0].num=1;//更新数值
	a[0].fl=1;
	bool error=0;//是否有负环
	int total=1;//总进堆次数
	while(heap[0]>=1)//堆中有数
	{
		int x=heap[1];//取出堆顶
		pop();
		a[x].fl=0;
		for(int i=a[x].last;i!=-1;i=e[i].next)//遍历每一条出边
		{
			int y=e[i].to;
			if(a[y].dis>a[x].dis+e[i].w)//松弛
			{
				a[y].dis=a[x].dis+e[i].w;
				if(a[y].fl)//如果y在堆中
				{
					down(a[y].pos);//调整
				}
				else
				{
					if((++a[y].num)==n+1||(++total)>=1000000)//判断是否有负环
					{
						error=1;
						break;
					}
					push(y);//插入y
					a[y].fl=1;
				}
			}
		}
		if(error)
		{
			break;
		}
	}
	if(error)//如果有负环(无解)
	{
		printf("-1");
	}
	else
	{
		printf("%d",a[n].dis);//输出答案
	}
	return 0;
}

总结

有时我们要将题目转化一下来得到解题的方法,如果我们想得多一些,可能解题的方法就简单一些。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(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、付费专栏及课程。

余额充值