首页 > 其他分享 >P1081[NOIP2012提高组]开车旅行

P1081[NOIP2012提高组]开车旅行

时间:2024-07-10 21:30:05浏览次数:17  
标签:旅行 NOIP2012 nn int netB long abs netA P1081

前两天老师还让我们狂做紫题,为什么今天就要求我们对这一道蓝题打暴力qwq

updata : 今天突然看到,这道题也是紫题了qwq

P1081 开车旅行

这道题一看就是dp一类的题,然后就会很顺畅的想到倍增awa

首先,看一下暴力怎么打。

这道题是当年的T4,然后有整整70分的暴力分,这是十分可观的awa。
所以,先想一下暴力。很容易想到先预处理,再模拟。

当然,如果你看不懂或是完全就不想看我写的这依托答辩,你可以直接去想想正解

以下是代码:


#include<bits/stdc++.h>
using namespace std;
int n,m;
long long x,a,b,s;
bool kk=0;
long long h[100005],l[100005],ll[100005];
long long netA[100005],netB[100005];
double Min=2000000009;
int main()
{
    h[0]=0x3f3f3f3f3f3f3f3f;
    
    cin>>n;
    for(int i=1;i<=n;i++)	cin>>h[i];
    for(int i=n-1;i>=1;i--)
    {
        long long mmin=i+1,mmin2=0;
        l[i]=abs(h[i]-h[i+1]);
        for(int j=i+2;j<=n;j++)
        {
            if(l[i]>abs(h[i]-h[j])||(l[i]==abs(h[i]-h[j])&&h[j]<h[mmin]))
            {
                ll[i]=l[i];
                l[i]=abs(h[i]-h[j]);
                mmin2=mmin;
                mmin=j;
            }
            else if(ll[i]==0||ll[i]>abs(h[i]-h[j])||(ll[i]==abs(h[i]-h[j])&&h[j]<h[mmin2]))
            {
                ll[i]=abs(h[i]-h[j]);
                mmin2=j;
            }
        }
        netA[i]=mmin;
        netB[i]=mmin2;
    }
    long long ans=0;
    cin>>x;
    for(int i=1;i<=n;i++)
    {
    	a=b=kk=0;
        long long fl=i;
        while(1)
        {
            if(kk)
            {
                if(a+b+l[fl]>x||!netA[fl])	break;
                b+=l[fl],fl=netA[fl];
            }
            else
            {
                if(a+b+ll[fl]>x||!netB[fl])	break;
                a+=ll[fl],fl=netB[fl];
            }
            kk^=1;
        }
        if(!ans||1.0*a/b-Min<-1e-9||(fabs(1.0*a/b-Min)<=1e-9&&h[ans]<h[i]))
			Min=1.0*a/b,ans=i;
    }
    cout<<ans<<'\n';
    cin>>m;
    while(m--)
	{
        a=b=kk=0;
        cin>>s>>x;
        while(1)
        {
            if(kk)
            {
                if(a+b+l[s]>x||!netA[s])	break;
                b+=l[s],s=netA[s];
        	}
            else
            {
                if(a+b+ll[s]>x||!netB[s])	break;
                a+=ll[s],s=netB[s];
            }
            kk^=1;
        }
		cout<<a<<" "<<b<<'\n';
    }
    return 0;
}

还是很容易看懂的吧awa?

好了,暴力已经打完了,我们已经有了70分,那么我们现在来想一下正解。

所以就开始想正解 $ dp $ :

首先,我们会发现 $ n,m $ 都很大,所以肯定是要预处理一部分内容,然后 $ O(1) $ 或者是 $ O(log n) $ 解答。

然后会发现,$ O(1) $ 是行不通的,因为 $ O(1) $ 一般是把一部分内容离线下来或者是直接对于所有的情况进行解答,然而 $ x $ 是每次给定的,并且范围是 $ 1e9 $ ,且没有共同性,所以不行。

那我们就来想一想别的方法:$ O(log n) $ 的方法。

可以发现,每一个点将会转移到的下一个点是已经固定的,然后还要$ log n $ 转移+找出答案,所以我们就可以很自然的想到倍增。

让我们来想一下怎么设 $ dp $ 状态:

设 $ f[i][j].x $ 为 $ 小A $ 从第 $ i $ 个点开始,向后驾车 $ 2^{j} $ 轮,能到哪里。

设 $ f[i][j].a $ 为$ 小A $ 从第 $ i $ 个点开始,向后驾车 $2^{j} $ 轮,$ 小A $ 开了多远。

设 f[i][j].b 为小A从第i个点开始,向后驾车 $2^{j}$ 轮,小B开了多远。

插一下数组解释:

$ netA[i] $ : 由 $ i $ 出发, $ 小A $ 驾车,下一个目的地是哪个点。

$ netB[i] $ : 由 $ i $ 出发, $ 小B $ 驾车,下一个目的地是哪个点。

转移显然:

$ f[i][j].x=f[i+f[i][j-1].x][j-1].x; $

$ f[i][j].a=f[i][j-1].a + f[i+f[i][j-1].x][j-1].a; $

$ f[i][j].b=f[i][j-1].b + f[i+f[i][j-1].x][j-1].b; $

但是!!!

有问题吗?

当然有

仔细思考一下,这个转移式子其实是有很大的问题的

其它的都还好,因为都是2的好几次方

但 $ f[i][0] $ 的意思是往后开一轮,这时,下一轮的司机就换成了 $ 小B $ 。

可状态里是都是 $ 小A $ 开始开车 $ qwq $ 。

所以问题大了 $ QAQ $

那么我们可以变一下 dp 定义:

设 $ f[0/1][i][j] $ 为从i这个点出发,向后驾车 $ 2^{j} $ 轮的各种状态

然后 $ [0/1] $ 代表:

$ 0 :小A $ 先开始开车

$ 1 :小B $ 先开始开车

那我们对于第二维等于 $ 0 $ 和 $ 1 $ 时特殊处理一下:


$ f[0][i][0].w=netA[i]; $

$ f[1][i][0].w=netB[i]; $

$ f[0][i][0].a=abs(h[netA[i]]-h[i]); $

$ f[1][i][0].b=abs(h[netB[i]]-h[i]); $


$ f[0][1][1].w=f[1][f[0][i][0].w][0].w;$

$ f[0][1][1].A=f[0][i][0].A+f[1][f[0][i][0].w][0].A;$

$ f[0][1][1].B=f[0][i][0].B+f[1][f[0][i][0].w][0].B;$


对于 $ j>=2 $ ,就只需要处理 $ f[0][i][j] $就可以了awa


$ f[0][i][j].w=f[0][i+f[0][i][j-1].x][j-1].w; $

$ f[0][i][j].a=f[0][i][j-1].a + f[0][i+f[0][i][j-1].w][j-1].a; $

$ f[0][i][j].b=f[0][i][j-1].b + f[0][i+f[0][i][j-1].w][j-1].b; $


这样就好了awa

然后这道题就结束了吗?

显然没有。

你仔细看一下我们打的暴力你就会发现:

我们在处理 $ netA[i] $ 和 $ netB[i] $ 时的复杂度时 $ O(n^2) $ 的,

所以我们也要将这里加速。

这里我的处理方法是倒序枚举,然后利用 $ set $ 查找前驱和后继。

最后:

代码如下:

#include<bits/stdc++.h>
using namespace std;
int n,m,ss,x0,w;
long long x;

long long hh;
double aans=-1;

int lt,nt;
long long lh,nh;
long long h[100005];
struct node{
   long long A,B;
   int w;
}f[2][100005][21];
struct nnode{
   int bh;
   long long h;
}nn;
bool operator<(nnode A,nnode B){
   return A.h<B.h;
}
set<nnode>s;
void init()
{
   h[0]=5e9;h[n+1]=-5e9;
   nn.bh=0;	nn.h=5e9;
   s.insert(nn);	s.insert(nn);
   nn.bh=n+1;	nn.h=-5e9;
   s.insert(nn);	s.insert(nn);
   nn.bh=n;	nn.h=h[n];
   s.insert(nn);
   for(int i=n-1;i>=1;i--)
   {
   	int ga,gb;
   	nn.bh=i;	nn.h=h[i];
   	s.insert(nn);
   	set<nnode>::iterator it=s.lower_bound(nn);
   	it--;
   	lt=(*it).bh;	lh=(*it).h;
   	it++,it++;
   	nt=(*it).bh;	nh=(*it).h;
   	it--;
   	if(abs(nh-h[i])>=abs(h[i]-lh))
   	{
   		gb=lt;
   		it--,it--;
   		if(abs(nh-h[i])>=abs(h[i]-(*it).h))	ga=(*it).bh;
   		else	ga=nt;
   	}
   	else
   	{
   		gb=nt;
   		it++,it++;
   		if(abs((*it).h-h[i])>=abs(h[i]-lh))	ga=lt;
   		else	ga=(*it).bh;
   	}
   	f[0][i][0].w=ga;
   	f[1][i][0].w=gb;
   	f[0][i][0].A=abs(h[ga]-h[i]);
   	f[1][i][0].B=abs(h[gb]-h[i]);
   }
   for(int i=1;i<=n;i++)
   {
   	f[0][i][1].w=f[1][f[0][i][0].w][0].w;
   	f[0][i][1].A=f[0][i][0].A+f[1][f[0][i][0].w][0].A;
   	f[0][i][1].B=f[0][i][0].B+f[1][f[0][i][0].w][0].B;
   }
   for(int j=2;j<=20;j++)
   {
   	for(int i=1;i<=n;i++)
   	{
   		f[0][i][j].w=f[0][f[0][i][j-1].w][j-1].w;
   		f[0][i][j].A=f[0][i][j-1].A+f[0][f[0][i][j-1].w][j-1].A;
   		f[0][i][j].B=f[0][i][j-1].B+f[0][f[0][i][j-1].w][j-1].B;
   	}
   }
}
node cl(int s,long long x)
{
   node now={0,0,0};
   for(int j=20;j>=0;j--)
   {
   	if(f[0][s][j].w&&now.A+now.B+f[0][s][j].A+f[0][s][j].B<=x)
   	{
   		now.A+=f[0][s][j].A;
   		now.B+=f[0][s][j].B;
   		s=f[0][s][j].w;
   	}
   }
   return now;
}
int main()
{
   cin>>n;
   for(int i=1;i<=n;i++)	cin>>h[i];
   init();
   cin>>x0;
   for(int i=1;i<=n;i++)
   {
   	node ans=cl(i,x0);
   	double C=((double)ans.A)/((double)(max(1ll,ans.B)));
   	if(aans==-1)	w=i,hh=h[i],aans=(ans.B==0?5e9:C);
   	else if(ans.B!=0)
   	{
   		if(aans>C)	aans=C,w=i,hh=h[i];
   		else if(aans==C&&h[i]>hh)	w=i,hh=h[i];
   	}
   	else if(aans==5e9&&h[i]>hh)	w=i,hh=h[i];
   }
   cout<<w<<'\n';
   cin>>m;
   for(int i=1;i<=m;i++)
   {
   	cin>>ss>>x;
   	node ans=cl(ss,x);
   	printf("%lld %lld\n",ans.A,ans.B);
   }
   return 0;
}

标签:旅行,NOIP2012,nn,int,netB,long,abs,netA,P1081
From: https://www.cnblogs.com/Jack-YT/p/18295063

相关文章

  • 同声传译app哪个好免费?5款旅行必备的实时翻译器
    暑假快到了,不得不说暑假就是要好朋友出去玩啊,谁还一整天都待在家里呢?若条件允许,跨出国门,领略异国风情,也是一个不错的选择。但语言障碍常常成为许多人心中的顾虑,担心自己的口语水平不足以畅游无忧。别担心,下面就为大家提供解决方案。今天给大家整理归纳了5个出国旅游必备的同......
  • 毕业旅行 oj题
    对于输入字符串:使用cincin适用于输入不包含空格的字符串。#include<iostream>usingnamespacestd;intmain(){charstr[1001];//字符数组大小为1001,留一个位置给'\0'cin>>str;cout<<"Youentered:"<<str<<endl;retur......
  • [题解]P1083 [NOIP2012 提高组] 借教室
    [题解]P1083[NOIP2012提高组]借教室解法\(1\):线段树-\(O((n+m)\logn)\)比较直观的一种做法,但是可能需要卡一下输入(这里没卡也过了,但要注意输入是\(10^6\)级的,为了保险一定要加)。#include<bits/stdc++.h>#definelc(x<<1)#definerc((x<<1)|1)#defineintlonglong......
  • P3350 [ZJOI2016] 旅行者
    咕了2天才写的题解还是比较经典的题目,分治处理网格图最短路离线下来,利用分治的思想,用一条线把网格图平均劈成两半,每次只考虑询问在两块的一对点,所有的线必须经过直线上的一个点,于是我把线上所有点都在规定范围内跑一次dijkstra,最后直接算答案,显然我想让最短路跑的次数最小,每次选......
  • 某程旅行安全工程师一面
    一、自我介绍阿吧阿吧,不多说了二、两段实习经历,看你在南京中孚数据安全部做实习生,你能大概讲一下做什么的吗当时做的是一个隐写溯源项目,是我们实验室跟南京中孚那边共同合作的。主要是针对电子文档信息泄露,数据泄密问题,开发涉密文档隐写溯源系统,实现敏感信息泄露追踪溯源技术,解......
  • 旅行商问题要点和难点以及具体应用案例
    旅行商问题(TravellingSalesmanProblem,TSP)是一个经典的组合优化问题,涉及给定一系列城市和每对城市之间的距离,求解访问每一座城市一次并回到起始城市的最短回路。这个问题在运筹学和理论计算机科学中非常重要,并且在多个领域有实际应用,如交通运输、电路板线路设计以及物流配送......
  • 奥赛一本通 旅行问题
    //旅行问题.cpp:此文件包含"main"函数。程序执行将在此处开始并结束。//#include<iostream>#include<deque>#include<cstring>usingnamespacestd;/*http://ybt.ssoier.cn:8088/problem_show.php?pid=1600原题来自:POI2004John打算驾驶一辆汽车周游一个环......
  • [DP] [倍增优化] Luogu P1081 [NOIP2012 提高组] 开车旅行
    [NOIP2012提高组]开车旅行题目描述小\(\text{A}\)和小\(\text{B}\)决定利用假期外出旅行,他们将想去的城市从$1$到\(n\)编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市\(i\)的海拔高度为\(h_i\),城市\(i\)和城市\(j\)之间的距......
  • 【旅行使身体和灵魂都在路上】智慧旅游解决方案集合推荐,干货满满!
    引言:2024年端午节假期,全国文化和旅游市场总体平稳有序。据测算,全国国内旅游出游合计1.1亿人次,同比增长6.3%;国内游客出游总花费403.5亿元,同比增长8.1%。假期中,群众赛龙舟、吃粽子、唱山歌、赏古曲,传统节日文化内涵与旅游发展深度融合。广东、湖南、浙江、贵州、云南等地......
  • 开车旅行|倍增优化dp+双端列表/set|题解
    题面:题面链接这题的思路值得借鉴,也是我做的第一道倍增优化dp题目.比较好的是题目的意思较为清晰,所以不再赘述.解析:这里我们可以非常直接的想到暴力模拟,因为第一眼看上去前七个点的数据范围是支持我们进行一个简单的预处理得到对应人在对应位置的决策的.(排序O(n×sqrt(......