首页 > 其他分享 >开车旅行|倍增优化dp+双端列表/set|题解

开车旅行|倍增优化dp+双端列表/set|题解

时间:2024-06-07 20:34:13浏览次数:29  
标签:set 20 双端 距离 题解 dp define

题面:

题面链接
这题的思路值得借鉴,也是我做的第一道倍增优化dp题目.
比较好的是题目的意思较为清晰,所以不再赘述.

解析:

这里我们可以非常直接的想到暴力模拟,因为第一眼看上去前七个点的数据范围是支持我们进行一个简单的预处理得到对应人在对应位置的决策的.
(排序O(n×sqrt(n))+对应位置决策处理O(n)).
这样之后模拟每个节点出发的全过程,以及它查询的各个信息的全过程,就可以得到对应答案了.
然后就考虑剩下的30怎么拿,其实我们既然有预处理的想法,就可以明白,既然我们在某一个点上两个人的决策是固定的且绑定的.
我们的起点,行走最大距离也固定,那么就可以用一个st表来优化我们的过程,走的距离大于对应距离就不跳,小于等于就转移.
这样到最后可以得到两个人在固定节点跳固定距离的最后终点与两个人行走的距离.
(由于两人操作绑定,在st表(sta)中用i表示在i点a跳一步的距离,在stb中用i表示a跳完之后b再跳一步的距离,而f存由i跳两步后的终点).

#include<bits/stdc++.h>
#define ll long long
#define qr qr()
#define pa pair<int,int>
#define fr first
#define sc second
#define ve vector<int>
#define lc tree[rt].ls
#define rc tree[rt].rs
#define Man What_can_I_say
using namespace std;
const int N=2e5+200,MN=50000;
double minn=2147483647;
int n,m,j,l,r,tot,p[N],head[N],sta[N][20],stb[N][20],f[N][20],na[N],nb[N],a,b,ans;
struct Man{
  int id,h,l,r;
  bool operator <(const Man & a) const
  {
  	return h<a.h;
  }
}ct[N<<2];
inline int qr
{
  int x=0;char ch=getchar();bool f=0;
  while(ch>57||ch<48)
  {
    if(ch=='-')f=1;
    ch=getchar();
  }
  while(ch<=57&&ch>=48)x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
  return f?-x:x;
}
bool check()
{
	if(!l) return 0;
	if(!r) return 1;
	return ct[j].h-ct[l].h<=ct[r].h-ct[j].h;
}
int pd(int a,int b)
{
	if(!a) return ct[b].id;
	if(!b) return ct[a].id;
	if(ct[j].h-ct[a].h<=ct[b].h-ct[j].h) return ct[a].id;
	return ct[b].id;
}
void pre_st()
{
	for(int j=1;j<=19;++j)
	{
		for(int i=1;i<=n;++i)
		{
			f[i][j]=f[f[i][j-1]][j-1];
			sta[i][j]=sta[i][j-1]+sta[f[i][j-1]][j-1];
			stb[i][j]=stb[i][j-1]+stb[f[i][j-1]][j-1];
		}
	}
}
void getab(ll x,int p)
{//这里其实就是我们所说的dp过程,其实也算不上dp吧.
	a=0,b=0;
	for(int i=19;i>=0;--i)
	{
		if(f[p][i]&&(a+b+sta[p][i]+stb[p][i])<=x)
		{
			a+=sta[p][i];
			b+=stb[p][i];
			p=f[p][i];
		}
	}
	if(na[p]&&a+b+sta[p][0]<=x)a+=sta[p][0];//还能再让a跳一步就让它跳.
}
void init()
{
	n=qr;
	ll x;
	for(int i=1;i<=n;++i)ct[i].h=qr;
	for(int i=1;i<=n;++i)ct[i].id=i;
	sort(ct+1,ct+n+1);
	for(int i=1;i<=n;++i)p[ct[i].id]=i;//离散化,找到每个原先的城市在排序后的位置
	for(int i=1;i<=n;++i)ct[i].l=i-1,ct[i].r=i+1;
	ct[1].l=ct[n].r=0;
	for(int i=1;i<=n;++i)
	{//这步是预处理的一部分,它是处理出每个位置上两个人的决策.
		j=p[i];l=ct[j].l;r=ct[j].r;
		if(check())nb[i]=ct[l].id,na[i]=pd(ct[l].l,r);
		else nb[i]=ct[r].id,na[i]=pd(l,ct[r].r);
		if(l) ct[l].r=r;//删掉一个节点
		if(r) ct[r].l=l;
	}
	for(int i=1;i<=n;++i)
	{//每个人的决策记录到st表对应位置.
		//注意一点就好,我们的stb数组它存储的是这个点上经过两步决策(两个人分别跑一步)之后b的行走距离,不是在i这个点上b一次决策的行走距离
		//因为我们调用的时候的第一步都是a来走,所以把b的操作也绑定在一起是方便的.
		f[i][0]=nb[na[i]];
		sta[i][0]=abs(ct[p[i]].h-ct[p[na[i]]].h);
		stb[i][0]=abs(ct[p[f[i][0]]].h-ct[p[na[i]]].h);
	}
	pre_st();
	x=qr,m=qr;
	for(int i=1;i<=n;++i)
	{
		getab(x,i);
		if(b&&1.0*a/b<minn)
		{
			minn=1.0*a/b;
			ans=i;
		}
	}
	printf("%d\n",ans);
	for(int i=1;i<=m;++i)
	{
		j=qr,x=qr;
		getab(x,j);
		printf("%d %d\n",a,b);
	}
}
int main()
{
  #ifndef ONLINE_JUDGE
  freopen("in.in","r",stdin);
  freopen("out.out","w",stdout);
  #endif
  init();
  return 0;
}

后记:

其实值得说的是双端列表,这里也是我第一次使用.
感觉上还是比较好理解的,用两个指针指向前后元素,删除插入操作只用动指针,排序后的系列操作用O(1)的优良复杂度解决.
好用.
另外是set解法,有时间会再加以补充.

标签:set,20,双端,距离,题解,dp,define
From: https://www.cnblogs.com/shining-like-stars/p/18237820

相关文章

  • ECharts数据集合(dataset)用法一(完整举例)
            数据集(dataset)是专门用来管理数据的组件。虽然每个系列都可以在series.data中设置数据,但是从ECharts4支持数据集开始,更推荐使用数据集来管理数据。因为这样,数据可以被多个组件复用,也方便进行“数据和其他配置”分离的配置风格。毕竟,在运行时,数据是最常改变的,而......
  • [ABC107D] Median of Medians 题解
    题目大意:一个长度为$M$的序列的中位数为这个序列从小到大排序后第$\lfloor\fracM2\rfloor+1$个数,将这个序列的所有子段的中位数放入一个序列中,求这个序列的中位数。设一个序列$a$的中位数为$x$,那么$a$中至少会有一半的数大于等于$x$,并且$x$是$a$中满足这个条件......
  • プログラミングコンテストチャレンジブック 题解
    题目大意:从$n$根木棒里选出六根拼成两个合法的三角形,使这两个三角形的周长和最大。考虑贪心,证明在后面。首先我们要知道一个三角形基本定理:较短两边长度之和大于最长边。那我们就根据这个定理先去寻找最大三角形的最长边。先排序,然后循环枚举,对于每个$a_i$,可以寻找到的最大......
  • [COCI2020-2021#2] Sjekira 题解
    题目大意:把一棵树完全分解,每次分解一条边的代价是这条边连接的两个连通块的最大点权之和,求最小代价。逆序模拟,既然题目要求将树完全分解,那我们就每次逆序连接当前权值最小的两个点,也就是贪心的思路。尝试将贪心的值写成一个表达式:$$\sum_{i=1}^na_i+\sum_{(u,v)\inE}\max(a......
  • [ABC036D] 塗り絵 题解
    题意题面讲挺清楚的就不简化了。思路树上求方案数,很明显是树上dp。设$dp_{i,0/1}$表示第$i$个点涂成白/黑色的方案数。当前结点如果为白色,那么它的子节点涂成什么颜色都没关系,根据分步乘法原理,将它子结点涂成白/黑色的方案数之和乘起来即可;当前结点如果为黑色,那么它的子......
  • [ABC126D] Even Relation 题解
    题意对一棵有$N$个点,$N-1$条边的树进行黑白染色,使得每两个距离为偶数的点颜色都一致。思路首先让我们回顾一下加法的性质:偶$+$偶$=$偶奇$+$奇$=$偶偶$+$奇$=$奇不难看出,距离为偶数的关系是可以传递的,而距离为奇数的关系不行。我们只需要做一遍dfs,对一个......
  • [ABC191E] Come Back Quickly 题解
    题面:给你一个$n$个点$m$条边的有向图,第$i$条边$a_i$,$b_i$,$c_i$,表示一条单向边从$a_i$到$b_i$,长度为$c_i$,可能会有重边和自环。问能否从第$i$号点出发然后回到该点形成一个环?可以则输出最短时间,否则输出$-1$。思路:不难发现本题考查的是最短路。观察题面,发现边数......
  • [ABC126F] XOR Matching 题解
    很好的构造题。题意请构造一个长度为$2^{m+1}$的序列$a$,该序列满足:$\foralli\in[1,2^{m+1}],a_i\in[0,2^m-1]$且每个数都恰好出现两次。对于任意一对$(i,j)$满足$a_i=a_j$,$a_i\oplusa_{i+1}\oplus\cdots\oplusa_{j-1}\oplusa_j=k$。$\oplus$表......
  • [ICML2022]Open-Sampling Exploring Out-of-Distribution Data for Re-balancing Long
    引入开集样本训练模型有点像dropout,“破坏”某些模型参数防止尾部类的过拟合Motivation长尾学习中的训练数据集分布不平衡的问题,解决方法之一是重采样。重采样主要对于尾部类重复采用,但这种做法往往会导致尾部类的过拟合。为了缓解过拟合[2](Rethinkingthevalueoflabelsf......
  • 食物链题解
    由题得,所有动物整体关系如上。起初每个动物相互时间没有关系,bb[i]=i。对于x与y:如果它们是同类即x到y的距离为$0$,或者转了几圈,一圈距离为$3$,即模$3$余$0$。如果x捕食y,就是x到y距离模$3$余$1$。对x与y操作时:如果它们没有关系(它们不被之前给出的某......