洛谷P1081——开车旅行
传送门: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——开车旅行的更多相关文章
- 洛谷 P1081 开车旅行(70)
P1081 开车旅行 题目描述 小AA 和小BB 决定利用假期外出旅行,他们将想去的城市从 11到 NN 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 ii的海 ...
- [NOIP2012] 提高组 洛谷P1081 开车旅行
题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 ...
- NOIP 2012 洛谷P1081 开车旅行
Description: 就是两个人开车,只能向东开.向东有n个城市,城市之间的距离为他们的高度差.A,B轮流开车,A喜欢到次近的城市,B喜欢到最近的城市.如果车子开到底了或者车子开的路程已经超过了限 ...
- 洛谷 P1081 开车旅行 —— 倍增
题目:https://www.luogu.org/problemnew/show/P1081 真是倍增好题! 预处理:f[i][j] 表示从 i 点开始走 2^j 次 AB (A,B各走一次)到达的点 ...
- 2018.11.04 洛谷P1081 开车旅行(倍增)
传送门 思路简单码量超凡? 感觉看完题大家应该都知道是倍增sbsbsb题了吧. 首先预处理出从每个点出发如果是AAA走到哪个点,如果是BBB走到哪个点. 然后利用刚刚预处理出的信息再预处理从每个点出发 ...
- 洛谷P1081 开车旅行(倍增)
题意 题目链接 Sol 咕了一年的题解.. 并不算是很难,只是代码有点毒瘤 \(f[i][j]\)表示从\(i\)号节点出发走了\(2^j\)轮后总的距离 \(da[i][j]\)同理表示\(a\)的 ...
- 洛谷P1081 开车旅行70分
https://www.luogu.org/problem/show?pid=1081 太遗憾了明明写出来了,却把最小值初始值弄小了,从第二个点开始就不可能对了.70分! #include<io ...
- 洛谷 P1081 开车旅行【双向链表+倍增】
倍增数组的20和N写反了反复WAWAWA-- 注意到a和b在每个点上出发都会到一个指定的点,所以这样构成了两棵以n点为根的树 假设我们建出了这两棵树,对于第一问就可以枚举起点然后倍增的找出ab路径长度 ...
- 洛谷P1081 开车旅行
题目 双向链表+倍增+模拟. \(70pts\): 说白了此题的暴力就是细节较多的模拟题. 我们设离\(i\)城市最近的点的位置为\(B[i]\),第二近的位置为\(A[i]\).设\(A\)或\(B ...
随机推荐
- ATC/TC/CF
10.25 去打 CF,然后被 CF 打了. CF EDU 75 A. Broken Keyboard 精神恍惚,WA 了一发. B. Binary Palindromes 比赛中的憨憨做法,考虑一个 ...
- Spring MVC @CookieValue注解(5)
@CookieValue的作用 用来获取Cookie中的值 @CookieValue参数 1.value:参数名称 2.required:是否必须 3.defaultValue:默认值 @Cookie ...
- 【学术篇】SDOI2010 古代猪文
这里可能包含传送门 又双叒叕数论大杂烩... 定理什么我都不会证 题目很长很啰嗦 但是题意很显然... 化完式子之后就是这么个东东:\(G^{\sum_{k|n}C_k^{\frac{n}{k}}}\ ...
- 【学术篇】SDOI2008 沙拉公主的困惑
传送门! 题目在这里... 题目大意? 难道不是说的很清楚了么OvO 求n!中与m!互质的数的个数.. 题目分析. 显然的数论... 所以就是化式子呗.. 一个很显然的性质就是如果\(gcd(a,b) ...
- Buy Low, Buy Lower
Buy Low, Buy Lower 给出一个长度为N序列\(\{a_i\}\),询问最长的严格下降子序列,以及这样的序列的个数,\(1 <= N <= 5000\). 解 显然我们可以很 ...
- P1820 寻找AP数
P1820 寻找AP数两个性质,分解质因数后,连续,且指数递减,dfs就完了 #include <iostream> #include <cstdio> #include &l ...
- Java 基础 - 内存泄露Memory leak & 内存溢出Out of memory
内存泄露 & 内存溢出 关系 https://www.cnblogs.com/panxuejun/p/5883044.html 内存泄露的6种情况: https://blog.csdn.net ...
- BZOJ 2957楼房重建
传送门 线段树 //Twenty #include<cstdio> #include<cstdlib> #include<iostream> #include< ...
- Docker系列(九):Kubernetes架构深度解析
Kubernetes重要概念 Docker解决了打包和隔离的问题,但我们需要更多:调度的问题,生命周期及健康状况,服务发现,监控,认证,容器聚合. Kubernetes概述 开源DOcker容器编排系 ...
- HDU-3068-最长回文-马拉车算法模板题
给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 回文就是正反读都是一样的字符串,如aba, abba等 Input输入有多组case,不超过120组,每组输入为 ...