传送门:QAQQAQ

题意注意点:

1.是从前往后走,不能回头

2.小A小B轮流开,先小A开,而小A是到第二近的点(这点调试的时候查了好久)

3.若绝对值差相同海拔低的更近,而第一个询问若比值相同是海拔高的更优

思路:我们先预处理出离i点最近和次近点的编号,没有就是-1(链表可以达到O(n),但是用STL O(nlog(n)) 绰绰有余,代码量还小)

然后用倍增预处理出从i号点走2^j轮A走的路程,B走的路程,和走完这些轮最终停下的点(定义AB各走一次为一轮)

注意可能走半轮,即最后一下A走B不走。

写题过程:

大佬MYY告诉我不要心急,先打70分暴力,然后打了2个小时暴力(STL真的好难查啊QAQ) 打完暴力以后告诉我主程序要全部删掉重写。。。。。

看到直接旁边的HCY没打暴力直接正解AC,心态崩了。。。

然后就在没有特判掉走不到的情况和AB顺序一半写正,一般写反上调了好久,不过最终做出来还是蛮有成就感的(感觉自己很弱啊。。)

代码:

#include<bits/stdc++.h>
#define m_k make_pair
#define ll long long
using namespace std;
const ll N=;
const ll inf=(ll)5e18; ll f[N][],n,m,a[N],x0;
//0:closest 1:second closest
ll dp[N][][],Bits[],p[N][];
//0:disB 1:disA p:finalpos AB为一轮,走2^t轮 ll _abs(ll x)
{
if(x<) return -x;
else return x;
} set<pair<ll,ll> > st;
vector<pair<ll,ll> > tmp;
void init()
{
memset(f,-,sizeof(f));
st.insert(m_k(a[n],n));
st.insert(m_k(a[n-],n-));
f[n-][]=n;
for(ll i=n-;i>=;i--)
{
ll bl=;
tmp.clear();
set<pair<ll,ll> > :: iterator it;
it=st.lower_bound(m_k(a[i],i));
if(it!=st.end()) tmp.push_back(*it),it++,bl++;
if(it!=st.end()) tmp.push_back(*it);
if(bl) it--;
it--;
set<pair<ll,ll> > :: iterator be;
be=st.begin(); be--;
if(it!=be) tmp.push_back(*it),it--;
if(it!=be) tmp.push_back(*it);
ll ans1=inf,ans2=inf;
for(ll j=;j<(ll)tmp.size();j++)
{
if(ans1>_abs(a[i]-tmp[j].first)||(ans1==_abs(a[i]-tmp[j].first)&&a[f[i][]]>tmp[j].first))
{
f[i][]=f[i][]; ans2=ans1;
f[i][]=tmp[j].second; ans1=_abs(a[i]-tmp[j].first);
}
else if(ans2>_abs(a[i]-tmp[j].first)||(ans2==_abs(a[i]-tmp[j].first)&&a[f[i][]]>tmp[j].first))
{
f[i][]=tmp[j].second; ans2=_abs(a[i]-tmp[j].first);
}
}
st.insert(m_k(a[i],i));
}
} void ready()
{
memset(p,-,sizeof(p));
memset(dp,-,sizeof(dp));
for(ll i=;i<=n;i++)
{
ll pos=f[i][]; if(pos==-) continue;
dp[i][][]=_abs(a[pos]-a[i]);
if(f[pos][]==-) continue;
dp[i][][]=_abs(a[pos]-a[f[pos][]]);
p[i][]=f[pos][];
}
for(ll j=;j<;j++)
{
for(ll i=;i<=n;i++)
{
for(ll k=;k<=;k++)
if(dp[i][j-][k]!=-&&dp[p[i][j-]][j-][k]!=-) dp[i][j][k]=dp[i][j-][k]+dp[p[i][j-]][j-][k];
if(p[i][j-]!=-) p[i][j]=p[p[i][j-]][j-]; }
}
} ll suma,sumb;
double calc(ll x,ll y)
{
if(y==) return inf*1.0;
return(x*1.0)/(y*1.0);
} int main()
{
scanf("%lld",&n);
for(ll i=;i<=n;i++) scanf("%lld",&a[i]);
init();
ready();
scanf("%lld",&x0);
double ans=inf*1.0;
ll now=;
a[]=-inf;
for(int i=;i<=n;i++)
{
ll suma=,sumb=,pos=i;
for(int j=;j>=;j--)
{
if(dp[pos][j][]==-||dp[pos][j][]==-||p[pos][j]==-) continue;
if(dp[pos][j][]+dp[pos][j][]+suma+sumb>x0) continue;
suma+=dp[pos][j][];
sumb+=dp[pos][j][];
pos=p[pos][j];
}
if(dp[pos][][]+suma+sumb<=x0&&dp[pos][][]!=-) suma+=dp[pos][][];
if(ans>calc(suma,sumb)||(ans==calc(suma,sumb)&&a[i]>a[now]))
{
now=i;
ans=calc(suma,sumb);
}
}
cout<<now<<endl; ll pos;
scanf("%lld",&m);
for(int i=;i<=m;i++)
{
scanf("%lld%lld",&pos,&x0);
suma=; sumb=;
for(int j=;j>=;j--)
{
if(dp[pos][j][]==-||dp[pos][j][]==-||p[pos][j]==-) continue;
if(dp[pos][j][]+dp[pos][j][]+suma+sumb>x0) continue;
suma+=dp[pos][j][];
sumb+=dp[pos][j][];
pos=p[pos][j];
}
if(dp[pos][][]+suma+sumb<=x0&&dp[pos][][]!=-) suma+=dp[pos][][];
printf("%lld %lld\n",suma,sumb);
}
return ;
}

洛谷P1081——开车旅行的更多相关文章

  1. 洛谷 P1081 开车旅行(70)

    P1081 开车旅行 题目描述 小AA 和小BB 决定利用假期外出旅行,他们将想去的城市从 11到 NN 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 ii的海 ...

  2. [NOIP2012] 提高组 洛谷P1081 开车旅行

    题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 ...

  3. NOIP 2012 洛谷P1081 开车旅行

    Description: 就是两个人开车,只能向东开.向东有n个城市,城市之间的距离为他们的高度差.A,B轮流开车,A喜欢到次近的城市,B喜欢到最近的城市.如果车子开到底了或者车子开的路程已经超过了限 ...

  4. 洛谷 P1081 开车旅行 —— 倍增

    题目:https://www.luogu.org/problemnew/show/P1081 真是倍增好题! 预处理:f[i][j] 表示从 i 点开始走 2^j 次 AB (A,B各走一次)到达的点 ...

  5. 2018.11.04 洛谷P1081 开车旅行(倍增)

    传送门 思路简单码量超凡? 感觉看完题大家应该都知道是倍增sbsbsb题了吧. 首先预处理出从每个点出发如果是AAA走到哪个点,如果是BBB走到哪个点. 然后利用刚刚预处理出的信息再预处理从每个点出发 ...

  6. 洛谷P1081 开车旅行(倍增)

    题意 题目链接 Sol 咕了一年的题解.. 并不算是很难,只是代码有点毒瘤 \(f[i][j]\)表示从\(i\)号节点出发走了\(2^j\)轮后总的距离 \(da[i][j]\)同理表示\(a\)的 ...

  7. 洛谷P1081 开车旅行70分

    https://www.luogu.org/problem/show?pid=1081 太遗憾了明明写出来了,却把最小值初始值弄小了,从第二个点开始就不可能对了.70分! #include<io ...

  8. 洛谷 P1081 开车旅行【双向链表+倍增】

    倍增数组的20和N写反了反复WAWAWA-- 注意到a和b在每个点上出发都会到一个指定的点,所以这样构成了两棵以n点为根的树 假设我们建出了这两棵树,对于第一问就可以枚举起点然后倍增的找出ab路径长度 ...

  9. 洛谷P1081 开车旅行

    题目 双向链表+倍增+模拟. \(70pts\): 说白了此题的暴力就是细节较多的模拟题. 我们设离\(i\)城市最近的点的位置为\(B[i]\),第二近的位置为\(A[i]\).设\(A\)或\(B ...

随机推荐

  1. 【ArcObject】 AxTocControl:实现图层可移动

    设置axTocControl属性:EnableLayerDragDrop 为true即可

  2. write -在一个文件描述符上执行写操作

    概述 #include <unistd.h> ssize_t write(int fd, const void *buf, size_t count); 描述 write 向文件描述符 f ...

  3. mysql-connetor-c 自动创建数据库、数据库表的命令

    1.首先连接MySQL默认的数据库mysql // 参数说明: // strIP: MySQL数据库的IP地址 // nPort: MySQL数据库的端口号 // strDBName: 要连接的数据库 ...

  4. 安装Epson打印机但因lsb依赖错误而中断的驱动程序

    sudo apt-get install printer-driver-escpr 安装Epson打印机但因lsb依赖错误而中断的驱动程序 问题: 我正在安装 Epson XP-310 驱动程序,从这 ...

  5. INSTALL_FAILED_TEST_ONLY oppor11p 安装时出现的问题

      刚开始出现这个问题 我很懵逼, 因为我之前一直运行都好好的  !!我在网上查了好多资料 试了好几种办法 我先说下我成功的办法       方法1: Android Studio 3.0会在debu ...

  6. 织梦怎么调用栏目SEO标题

    点击[模板][默认模板管理]找到模板文件名[list_article.htm],点击模板后面的修改,弹出修改模板代码页面.更改模板文件中<title>{dede:field.title/} ...

  7. SQL Server [join] 整理

    [表A]Aid    Aname   Acode1       aa      0012       bb      0023       cc      0034       dd      004 ...

  8. Redis-GEO

    一. Redis的GEO特性 Redis3.2版本提供了GEO功能,支持存储地理位置信息用来实现诸如摇一摇,附近位置这类依赖于地理位置信息的功能.二. 命令2.1 增加地理位置信息 命令:geoadd ...

  9. 如何HOOK桌面窗口消息

    代码详见:http://download.csdn.net/detail/swanabin/6771465 需求:截获桌面窗口鼠标单击事件,解析所选中的桌面 Item,并将解析后的 item 信息发送 ...

  10. shell脚本练习04

    ######################################################################### # File Name: -.sh # Author ...