开车旅行
- 关键字:链表,倍增
结果和评价
得分:70
时间:40+60
- 评价 :代码功底很一般。
我的思路
量化
- 我们需要处理的就是两个东西。
- 怎么快速的求出每个点对于的 tA[i] , tB[i] 表示在i点不同的人开车会到达的点。
- 然后就是怎么高效的模拟出开车过程了。
分析
70
- 对于第一个问题。我们可以 O(n2) 扫一下
void init(){
For(x,1,n){
int a=0,b=0;
For(j,x+1,n){
int d=abs(h[j]-h[x]);
if((!a)||(d<abs(h[a]-h[x]))||(d==abs(h[a]-h[x])&&h[j]<h[a]))b=a,a=j;
else if((!b)||(d<abs(h[b]-h[x]))||(d==abs(h[b]-h[x])&&h[j]<h[b]))b=j;
}
tA[x]=b,tB[x]=a;
}
}
- 然后模拟的过程直接 O(n) 模拟地跳即可。
void solve(int x,int limt,bool Ot=1){
int a=0,b=0;
bool f=0;/*!f -> A*/
int cur=x;
int res=limt;
while(res){
if(!f){
int nxt=tA[cur];
int d=abs(h[cur]-h[nxt]);
if(!nxt)break;
else if(d>res)break;
else a+=d,res-=d;
cur=nxt;
}
else {
int nxt=tB[cur];
int d=abs(h[cur]-h[nxt]);
if(!nxt)break;
else if(d>res)break;
else b+=d,res-=d;
cur=nxt;
}
f=!f;
}
if(Ot)pt(a),ptn(b);
else {
if(!b)bi[x]=INF;
else bi[x]=1.0*a/b;/*用于回答第一个询问*/
}
}
100
对于第二个过程。可以使用倍增高效优化
定义:
to[i][j] 表示从 i 出发,
A,B 都跳 2j−1 次回到达的点。cA[i][j] , cB[i][j] 分别表示到达该点, A,B 各自需要的里程。
处理
For(i,1,n){ to[i][0]=tB[tA[i]]; cA[i][0]=abs(h[tA[i]]-h[i]); cB[i][0]=abs(h[to[i][0]]-h[tA[i]]); } For(j,1,N)For(i,1,n)to[i][j]=to[to[i][j-1]][j-1]; For(j,1,N)For(i,1,n)if(to[i][j])cA[i][j]=cA[i][j-1]+cA[to[i][j-1]][j-1]; For(j,1,N)For(i,1,n)if(to[i][j])cB[i][j]=cB[i][j-1]+cB[to[i][j-1]][j-1];
然后每次跳跃就可以做到 log(n) 了
void solve(int x,int limt,bool Ot=1){ int s=x; ll a=0,b=0; Ror(i,0,N){ if(to[x][i]&&a+b+cA[x][i]+cB[x][i]<=limt) a+=cA[x][i],b+=cB[x][i],x=to[x][i]; } int to=tA[x]; if(to){ int d=abs(h[x]-h[to]); if(d+a+b<=limt)a+=d; } if(Ot)pt(a),ptn(b); else { if(!b)bi[x]=INF; else { bi[s]=1.0*a/b; } } }
好了,我们现在需要的就是如何高效的求 tA,tB 数组了。。。怎么搞
- 量化一下
- 对于一个
x
我们需要求出的其实就是在
[x+1,n] 范围里 abs(h[x]−h[i]) 最小的几个。 - 很直观的,可以使用
set
,从
n
到
1 扫过了,然后每次 bound 一下取出需要的元素
我们™的比赛的时候写了 set ,没有搞出来,赛后调了1个多小时也可以调出来。。恶心了
- 其实可以使用简单的双向链表来实现这一操作的。
- 因为我们只要求出 x 在权值上的前驱和后继即可
- 所以,我们可以先排序,然后
O(n) 维护。 - 我们用
rnk[i]
表示权值第
i
小的点,然后用
ord[i] 表示第 i 个点排第几即可。 - 然后从左向右扫,每次询问完了以后把自己从链表中删除即可。
void init(){
For(i,1,n)rnk[i]=i;
sort(rnk+1,rnk+1+n,cmp);
For(i,1,n)ord[rnk[i]]=i;
For(i,1,n)bug(i),debug(rnk[i]);
For(i,1,n-1)nxt[i]=i+1;
For(i,2,n)pre[i]=i-1;
For(i,1,n){
int x=ord[i];
check(i,rnk[pre[x]]);
check(i,rnk[pre[pre[x]]]);
check(i,rnk[nxt[x]]);
check(i,rnk[nxt[nxt[x]]]);
if(pre[x])nxt[pre[x]]=nxt[x];
if(nxt[x])pre[nxt[x]]=pre[x];
}
For(i,1,n){
to[i][0]=tB[tA[i]];
cA[i][0]=abs(h[tA[i]]-h[i]);
cB[i][0]=abs(h[to[i][0]]-h[tA[i]]);
}
For(j,1,N)For(i,1,n)to[i][j]=to[to[i][j-1]][j-1];
For(j,1,N)For(i,1,n)if(to[i][j])cA[i][j]=cA[i][j-1]+cA[to[i][j-1]][j-1];
For(j,1,N)For(i,1,n)if(to[i][j])cB[i][j]=cB[i][j-1]+cB[to[i][j-1]][j-1];
}
实现
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<time.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<bitset>
#include<map>
#include<string>
using namespace std;
#define bug(x) cerr<<#x<<'='<<x<<' '
#define debug(x) cerr<<#x<<'='<<x<<'\n'
#define For(i,a,b) for(int i=a;i<=b;++i)
#define Ror(i,a,b) for(int i=b;i>=a;--i)
typedef long long ll;
template<class T>void rd(T&x){
x=0;char c,f=1;
while(c=getchar(),!isdigit(c))if(c=='-')f=-1;
do x=(x<<3)+(x<<1)+(c^'0');
while(c=getchar(),isdigit(c));
x*=f;
}
template<class T>void pf(T x){
static int top=0,stk[100];
if(!x)putchar('0');
if(x<0)putchar('-'),x=-x;
while(x)stk[++top]=x%10,x/=10;
while(top)putchar(stk[top--]+'0');
}
template<class T>void pt(T x){pf(x);putchar(' ');}
template<class T>void ptn(T x){pf(x);putchar('\n');}
template<class T>void Max(T&x,T y){if(x<y)x=y;}
template<class T>void Min(T&x,T y){if(y<x)x=y;}
const int M=100005,N=19;
const double INF=1e9;
ll h[M],tA[M],tB[M],to[M][20],cA[M][20],cB[M][20],n,m;
double bi[M];
struct P{
int h,id;
bool operator<(const P&A)const{
if(h!=A.h)return h<A.h;
return id<A.id;
}
};
multiset<P>S;
multiset<P>::iterator it1,it2,it3,it4;
int rnk[M],nxt[M],pre[M],ord[M];
bool cmp(int a,int b){return h[a]<h[b];}
void check(int x,int j){
if(!j)return;
ll &b=tA[x],&a=tB[x];
int d=abs(h[j]-h[x]);
if((!a)||(d<abs(h[a]-h[x]))||(d==abs(h[a]-h[x])&&h[j]<h[a]))b=a,a=j;
else if((!b)||(d<abs(h[b]-h[x]))||(d==abs(h[b]-h[x])&&h[j]<h[b]))b=j;
}
struct P2{
void init(){
For(i,1,n)rnk[i]=i;
sort(rnk+1,rnk+1+n,cmp);
For(i,1,n)ord[rnk[i]]=i;
For(i,1,n)bug(i),debug(rnk[i]);
For(i,1,n-1)nxt[i]=i+1;
For(i,2,n)pre[i]=i-1;
For(i,1,n){
int x=ord[i];
check(i,rnk[pre[x]]);
check(i,rnk[pre[pre[x]]]);
check(i,rnk[nxt[x]]);
check(i,rnk[nxt[nxt[x]]]);
if(pre[x])nxt[pre[x]]=nxt[x];
if(nxt[x])pre[nxt[x]]=pre[x];
}
For(i,1,n){
to[i][0]=tB[tA[i]];
cA[i][0]=abs(h[tA[i]]-h[i]);
cB[i][0]=abs(h[to[i][0]]-h[tA[i]]);
}
For(j,1,N)For(i,1,n)to[i][j]=to[to[i][j-1]][j-1];
For(j,1,N)For(i,1,n)if(to[i][j])cA[i][j]=cA[i][j-1]+cA[to[i][j-1]][j-1];
For(j,1,N)For(i,1,n)if(to[i][j])cB[i][j]=cB[i][j-1]+cB[to[i][j-1]][j-1];
}
void solve(int x,int limt,bool Ot=1){
int s=x;
ll a=0,b=0;
Ror(i,0,N){
if(to[x][i]&&a+b+cA[x][i]+cB[x][i]<=limt)
a+=cA[x][i],b+=cB[x][i],x=to[x][i];
}
int to=tA[x];
if(to){
int d=abs(h[x]-h[to]);
if(d+a+b<=limt)a+=d;
}
if(Ot)pt(a),ptn(b);
else {
if(!b)bi[x]=INF;
else {
bi[s]=1.0*a/b;
}
}
}
void work(){
init();
int k=0,x,s;
rd(x);
For(i,1,n)solve(i,x,0);
For(i,1,n)if(!k||(bi[k]>bi[i])||((bi[k]==bi[i])&&h[k]<h[i]))k=i;
rd(m);
ptn(k);
For(i,1,m){
rd(s),rd(x);
solve(s,x);
}
}
}P2;
int main(){
// freopen("drive.in","r",stdin);
// freopen("drive.out","w",stdout);
rd(n);
For(i,1,n)rd(h[i]);
P2.work();
return 0;
}
反思
stl 有毒的,没有很好的代码功底。。不要轻易使用。- stl 的复杂度都比较大,而且可能容易出错的,如果可以使用其他的算法,竟可能用其他的算法
- 总之, stl 是最后没有办法的办法。。。了
其实,还是自己太辣鸡了。。。。T_T