列表

详情


NC16562. [NOIP2012]开车旅行

描述

小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi ,城市 i 和城市 j 之间的距离 d[i,j] 恰好是这两个城市海拔高度之差的绝对值,即 d[i,j]=|Hi-Hj|
旅行过程中,小 A 和小 B 轮流开车,第一天小 A 开车,之后每天轮换一次。他们计划选择一个城市 S 作为起点,一直向东行驶,并且最多行驶 X 公里就结束旅行。小 A 和小 B 的驾驶风格不同,小 B 总是沿着前进方向选择一个最近的城市作为目的地,而小 A 总是沿着前进方向选择第二近的城市作为目的地(注意:本题中如果当前城市到两个城市的距离相同,则认为离海拔低的那个城市更近)。如果其中任何一人无法按照自己的原则选择目的城市,或者到达目的地会使行驶的总距离超出 X 公里,他们就会结束旅行。
在启程之前,小 A 想知道两个问题:
1.对于一个给定的 X=X0 ,从哪一个城市出发,小 A 开车行驶的路程总数与小 B 行驶的路程总数的比值最小(如果小 B 的行驶路程为 0 ,此时的比值可视为无穷大,且两个无穷大视为相等)。如果从多个城市出发,小 A 开车行驶的路程总数与小 B 行驶的路程总数的比值都最小,则输出海拔最高的那个城市。
2.对任意给定的 X=Xi 和出发城市 Si ,小 A 开车行驶的路程总数以及小 B 行驶的路程总数。

输入描述

第一行包含一个整数 N ,表示城市的数目。
第二行有 N 个整数,每两个整数之间用一个空格隔开,依次表示城市 1 到城市 N 的海拔高度,即 H1,H2,…,Hn ,且每个 Hi 都是不同的。
第三行包含一个整数 X0
第四行为一个整数 M ,表示给定 M 组 Si 和 Xi
接下来的 M 行,每行包含 2 个整数 Si 和 Xi ,表示从城市 Si 出发,最多行驶 Xi 公里。

输出描述

输出共 M+1 行。
第一行包含一个整数 S0 ,表示对于给定的 X0 ,从编号为 S0 的城市出发,小 A 开车行驶的路程总数与小 B 行驶的路程总数的比值最小。
接下来的 M 行,每行包含 2 个整数,之间用一个空格隔开,依次表示在给定的 Si 和 Xi 下小 A 行驶的里程总数和小 B 行驶的里程总数。

示例1

输入:

4
2 3 1 4
3
4
1 3
2 3
3 3
4 3

输出:

1
1 1
2 0
0 0
0 0

说明:


各个城市的海拔高度以及两个城市间的距离如上图所示。
如果从城市 1 出发,可以到达的城市为 2,3,4 ,这几个城市与城市 1 的距离分别为 1,1,2 ,但是由于城市 3 的海拔高度低于城市 2 ,所以我们认为城市 3 离城市 1 最近,城市 2 离城市 1 第二近,所以小A会走到城市 2 。到达城市 2 后,前面可以到达的城市为 3,4 ,这两个城市与城市 2 的距离分别为 2,1 ,所以城市 4 离城市 2 最近,因此小B会走到城市 4 。到达城市 4 后,前面已没有可到达的城市,所以旅行结束。
如果从城市 2 出发,可以到达的城市为 3,4 ,这两个城市与城市 2 的距离分别为 2,1 ,由于城市 3 离城市 2 第二近,所以小A会走到城市 3 。到达城市 3 后,前面尚未旅行的城市为 4 ,所以城市 4 离城市 3 最近,但是如果要到达城市 4 ,则总路程为 2+3=5>3 ,所以小B会直接在城市 3 结束旅行。
如果从城市 3 出发,可以到达的城市为 4 ,由于没有离城市 3 第二近的城市,因此旅行还未开始就结束了。

示例2

输入:

10
4 5 6 1 2 3 7 8 9 10
7
10
1 7
2 7
3 7
4 7
5 7
6 7
7 7
8 7
9 7
10 7

输出:

2
3 2
2 4
2 1
2 4
5 1
5 1
2 1
2 0
0 0
0 0

说明:

当 X=7 时,如果从城市 1 出发,则路线为 1 → 2 → 3 → 8 → 9 ,小A走的距离为 1+2=3 ,小B走的距离为 1+1=2 。(在城市 1 时,距离小A最近的城市是 2 和 6 ,但是城市 2 的海拔更高,视为与城市 1 第二近的城市,所以小A最终选择城市 2 ;走到 9 后,小A只有城市 10 可以走,没有第 2 选择可以选,所以没法做出选择,结束旅行)
如果从城市 2 出发,则路线为 2 → 6 → 7 ,小A和小B走的距离分别为 2,4 。
如果从城市 3 出发,则路线为 3 → 8 → 9 ,小A和小B走的距离分别为 2,1 。
如果从城市 4 出发,则路线为 4 → 6 → 7 ,小A和小B走的距离分别为 2,4 。
如果从城市 5 出发,则路线为 5 → 7 → 8 ,小A和小B走的距离分别为 5,1 。
如果从城市 6 出发,则路线为 6 → 8 → 9 ,小A和小B走的距离分别为 5,1 。
如果从城市 7 出发,则路线为 7 → 9 → 10 ,小A和小B走的距离分别为 2,1 。
如果从城市 8 出发,则路线为 8 → 10 ,小A和小B走的距离分别为 2,0 。
如果从城市 9 出发,则路线为 9 ,小A和小B走的距离分别为 0,0 (旅行一开始就结束了)。
如果从城市 10 出发,则路线为 10 ,小A和小B走的距离分别为 0,0 。
从城市 2 或者城市 4 出发小A行驶的路程总数与小B行驶的路程总数的比值都最小,但是城市 2 的海拔更高,所以输出第一行为 2 。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 202ms, 内存消耗: 80328K, 提交时间: 2022-08-11 16:30:27

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=100010;
struct node{
    int id,v,l,r;
    bool operator < (const node &a) const{
        return v<a.v;
    }
}d[maxn];
int sta[maxn][31],stb[maxn][31],f[maxn][31],n,p[maxn],na[maxn],nb[maxn];
double minn=2147483647;
inline bool lf(int now,int l,int r){
    if(!l) return 0;
    if(!r) return 1;
    return d[now].v-d[l].v<=d[r].v-d[now].v;
}
inline int zzz(int now,int x,int y){
    if(!x) return d[y].id;
    if(!y) return d[x].id;
    if(d[now].v-d[x].v<=d[y].v-d[now].v) return d[x].id;
    return d[y].id;
}
inline void stwork(){
    for(int j=1;j<20;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];
        }
}
int a,b;
inline void gtab(long long x,int p){
    a=b=0;
    for(int i=19;i>=0;i--)
        if(f[p][i] && (long long)(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];
}
signed main()
{
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&d[i].v);
    for(int i=1;i<=n;i++)
        d[i].id=i;
    sort(d+1,d+1+n);
    for(int i=1;i<=n;i++)
        p[d[i].id]=i;
    for(int i=1;i<=n;i++)
        d[i].l=i-1,d[i].r=i+1;
    d[1].l=d[n].r=0;
    for(int i=1;i<=n;i++){
        int now=p[i],l=d[now].l,r=d[now].r;
        if(lf(now,l,r)) nb[i]=d[l].id,na[i]=zzz(now,d[l].l,r);
        else nb[i]=d[r].id,na[i]=zzz(now,l,d[r].r);
        if(l) d[l].r=r;
        if(r) d[r].l=l;
    }
    for(int i=1;i<=n;i++){
        f[i][0]=nb[na[i]];
        sta[i][0]=abs(d[p[i]].v-d[p[na[i]]].v);
        stb[i][0]=abs(d[p[f[i][0]]].v-d[p[na[i]]].v);
    }
    stwork();
    int x,m,ans,y;
    scanf("%lld%lld",&x,&m);
    for(int i=1;i<=n;i++){
        gtab(x,i);
        if(b && 1.0*a/b < minn)
            minn=1.0*a/b,ans=i;
    }
    printf("%lld\n",ans);
    for(int i=1;i<=m;i++){
        scanf("%lld%lld",&x,&y);
        gtab(y,x);
        printf("%lld %lld\n",a,b);
    }
    return 0;
}

C++14(g++5.4) 解法, 执行用时: 387ms, 内存消耗: 78308K, 提交时间: 2019-11-20 22:25:05

#include<iostream>
#include<cstring>
#include<set>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;

const int INF = 0x7fffffff;
const int maxn = 1e5 + 100;
typedef long long LL;

struct note{
	LL h,_abs;
}t[5];
set<LL>s;
map<LL,LL>mp;
LL n,h[maxn],a[maxn],b[maxn],fa[maxn],fb[maxn],sa[maxn][25],sb[maxn][25],f[maxn][25];

bool cmp(note aa,note bb)
{
	return (aa._abs==bb._abs?aa.h<bb.h:aa._abs<bb._abs);
}

void st()
{
	for(LL i=n;i>=1;i--)
	{
		s.insert(h[i]);
		t[1].h = *--s.lower_bound(h[i]);
		t[3].h = *--s.lower_bound(t[1].h);
		t[2].h = *s.upper_bound(h[i]);
		t[4].h = *s.upper_bound(t[2].h);
		for(LL j=1;j<=4;j++)
			t[j]._abs = abs(t[j].h-h[i]);
		sort(t+1,t+5,cmp);
		a[i] = t[2]._abs;
		fa[i] = mp[t[2].h];
		b[i] = t[1]._abs;
		fb[i]= mp[t[1].h];
		if(fa[i])
		{
			sa[i][0] = a[i];
			f[i][0] = fa[i];
		}
		if(fb[fa[i]])
		{
			sa[i][1] = a[i];
			sb[i][1] = b[fa[i]];
			f[i][1] = fb[fa[i]];
		}
		for(LL j=2;j<=16;j++)
			if(f[ f[i][j-1]  ][j-1])
			{
				sa[i][j] = sa[i][j-1] + sa[f[i][j-1]][j-1];
				sb[i][j] = sb[i][j-1] + sb[f[i][j-1]][j-1];
				f[i][j] = f[f[i][j-1]][j-1];
			}
			else break;
	}
}

double ask1(LL x,LL p)
{
	LL s1 = 0,s2 = 0;
	for(LL i=16;i>=0;i--)
	{
		if(f[x][i]&&s1+s2+sa[x][i]+sb[x][i]<=p)
		{
			s1 += sa[x][i];
			s2 += sb[x][i];
			x = f[x][i];
		}
	}
	return s2==0?INF:(double)s1/(double)s2;
}

void ask2(LL x,LL p)
{
	LL s1 = 0;
	LL s2 = 0;
	for(LL i=16;i>=0;i--)
		if(f[x][i] && s1+s2+sa[x][i]+sb[x][i]<=p)
		{
			s1 += sa[x][i];
			s2 += sb[x][i];
			x = f[x][i];
		}
	if(fa[x]&&s1+s2+sa[x][0]<=p) s1 += sa[x][0];
	printf("%lld %lld\n",s1,s2);
}

void solve()
{
	double minn = INF;
	LL bj,x0;
	scanf("%lld",&x0);
	for(LL i=1;i<=n;i++)
	{
		double op = ask1(i,x0);
		if(op<minn)
		{
			minn = op;
			bj = i;
		}
	}
	printf("%lld\n",bj);
	LL m,s0;
	scanf("%lld",&m);
	while(m--)
	{
		scanf("%lld%lld",&s0,&x0);
		ask2(s0,x0);
	}
}

int main()
{
	s.insert(INF);
	s.insert(INF-1);
	s.insert(-INF);
	s.insert(-INF+1);
	scanf("%lld",&n);
	for(LL i=1;i<=n;i++)
	{
		scanf("%lld",&h[i]);
		mp[h[i]] = i;
	}
	st();
	solve();
	return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 389ms, 内存消耗: 78200K, 提交时间: 2019-11-16 18:30:58

#include<bits/stdc++.h>
#define INF 50000000000LL
#define A 100005
using namespace std;
struct note{
	long long h,_abs;
}t[5];
set<long long>s;
map<long long,long long>mp;
long long n,h[A],a[A],b[A],fa[A],fb[A],sa[A][25],sb[A][25],f[A][25];
bool cmp(note aa,note bb){
	return (aa._abs==bb._abs?aa.h<bb.h:aa._abs<bb._abs);
}
void st(){
	for(long long i=n;i>=1;i--){
		s.insert(h[i]);
		t[1].h=*--s.lower_bound(h[i]);
        t[3].h=*--s.lower_bound(t[1].h); 
        t[2].h=*s.upper_bound(h[i]); 
		t[4].h=*s.upper_bound(t[2].h);
		for(long long j=1;j<=4;j++)t[j]._abs=abs(t[j].h-h[i]);
		sort(t+1,t+5,cmp);
		a[i]=t[2]._abs;fa[i]=mp[t[2].h];
		b[i]=t[1]._abs;fb[i]=mp[t[1].h];
//		s.insert(h[i]);
		if(fa[i])sa[i][0]=a[i],f[i][0]=fa[i];
		if(fb[fa[i]])sa[i][1]=a[i],sb[i][1]=b[fa[i]],f[i][1]=fb[fa[i]];
		for(long long j=2;j<=16;j++)
			if(f[f[i][j-1]][j-1]){
				sa[i][j]=sa[i][j-1]+sa[f[i][j-1]][j-1];
				sb[i][j]=sb[i][j-1]+sb[f[i][j-1]][j-1];
				f[i][j]=f[f[i][j-1]][j-1];
			}
			else break;
	}
}
double ask1(long long x,long long p){
	long long s1=0,s2=0;
	for(long long i=16;i>=0;i--){
		if(f[x][i]&&s1+s2+sa[x][i]+sb[x][i]<=p){
			s1+=sa[x][i];
			s2+=sb[x][i];
			x=f[x][i];
		}
	}
	return (s2==0?INF:(double)s1/(double)s2);
}
void ask2(long long x,long long p){
	long long s1=0,s2=0;
	for(long long i=16;i>=0;i--){
		if(f[x][i]&&s1+s2+sa[x][i]+sb[x][i]<=p){
			s1+=sa[x][i];
			s2+=sb[x][i];
			x=f[x][i];
		}
	}
	if(fa[x]&&s1+s2+sa[x][0]<=p)s1+=sa[x][0];
	printf("%lld %lld\n",s1,s2);
}
void solve(){ 
	double minn=INF;
	long long bj,x0;
	scanf("%lld",&x0);
	for(long long i=1;i<=n;i++){
		double op=ask1(i,x0);
		if(op<minn)minn=op,bj=i;
	}
	printf("%lld\n",bj);
	long long m,s0;
	scanf("%lld",&m);
	while(m--){
		scanf("%lld%lld",&s0,&x0);
		ask2(s0,x0);
	}
}
int main(){
	s.insert(INF);s.insert(INF-1);s.insert(-INF);s.insert(-INF+1);
	scanf("%lld",&n);
	for(long long i=1;i<=n;i++)scanf("%lld",&h[i]),mp[h[i]]=i;
	st();
	solve();
	return 0;
}

上一题