zoukankan      html  css  js  c++  java
  • 【vijos1780】【NOIP2012】开车旅行 倍增

    题目描述

      有(n)个城市,第(i)个城市的海拔为(h_i)且这(n)个城市的海拔互不相同。编号比较大的城市在东边。两个城市(i,j)之间的距离为(|h_i-h_j|)

      小A和小B要开车去旅行。小A先开,他们会轮流开车。小A会把车开到第二近的城市,小B会把车开到最近的城市。如果当前城市到两个城市的距离相同,则认为海拔低的城市比较近。他们只会把车往东边开(即编号大的那边)。

      小A会先问你对于一个给定的(x=x_0),从哪一个城市出发,小A开车行驶的路程总数与小B行驶的路程总数的比值最小(如果小B的行驶路程为(0),此时的比值可视为无穷大,且两个无穷大视为相等)。如果从多个城市出发,小A开车行驶的路程总数与小B行驶的路程总数的比值都最小,则输出海拔最高的那个城市。

      他还会问你(m)次。每次要你求出对给定的(x=x_i) 和出发城市(s_i),小A开车行驶的路程总数以及小B行驶的路程总数。

      (nleq 100000,mleq 10000)

    题解

      先用set求出当前在第(i)个城市时小A会把车开到哪个城市和小B会把车开到那个城市。

      然后倍增。(fa_{i,j})表示当前在第(i)个城市时开(2^j)轮(小A和小B各开一次算一轮)后小A开车的距离,(f_b{i,j})表示当前在第(i)个城市时开(2^j)轮后小B开车的距离。(g_{i,j})表示当前在第(i)个城市时开(2^j)轮后会到达哪里。

      现在我们要求当前在第(s)个城市,开不超过(x)公里,小A开车的路程和小B开车的路程。显然直接倍增就可以了,还要加上不满一轮的情况,即开若干轮后小A再开一次。

      第一问直接枚举起点,计算答案。

      第二问直接计算答案。

      时间复杂度:(O((n+m)log n))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #include<utility>
    #include<set>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,int> pli;
    ll h[100010];
    set<pli> ht;
    int na[100010];
    int nb[100010];
    ll fa[100010][20];
    ll fb[100010][20];
    int g[100010][20];
    int getmin(ll v)
    {
    	if(ht.size()==0)
    		return -1;
    	set<pli>::iterator p=ht.lower_bound(pli(v,0));
    	if(p==ht.begin())
    		return p->second;
    	if(p==ht.end())
    	{
    		p--;
    		return p->second;
    	}
    	pii s1=*p;
    	s1.first-=v;
    	p--;
    	pii s2=*p;
    	s2.first=v-s2.first;
    	if(s1.first<s2.first)
    		return s1.second;
    	return s2.second;
    }
    struct p
    {
    	int x;
    	double s;
    };
    double inf=1e100;
    int main()
    {
    	freopen("vijos1780.in","r",stdin);
    	freopen("vijos1780.out","w",stdout);
    	int n;
    	scanf("%d",&n);
    	int i,j;
    	for(i=1;i<=n;i++)
    		scanf("%lld",&h[i]);
    	for(i=n;i>=1;i--)
    	{
    		nb[i]=getmin(h[i]);
    		if(nb[i]==-1)
    			na[i]=-1;
    		else
    		{
    			ht.erase(ht.find(pii(h[nb[i]],nb[i])));
    			na[i]=getmin(h[i]);
    			ht.insert(pii(h[nb[i]],nb[i]));
    		}
    		ht.insert(pii(h[i],i));
    	}
    	for(i=1;i<=n;i++)
    		if(na[i]==-1)
    		{
    			g[i][0]=i;
    			fa[i][0]=fb[i][0]=0;
    		}
    		else if(nb[na[i]]==-1)
    		{
    			g[i][0]=na[i];
    			fa[i][0]=abs(h[i]-h[na[i]]);
    			fb[i][0]=0;
    		}
    		else
    		{
    			g[i][0]=nb[na[i]];
    			fa[i][0]=abs(h[i]-h[na[i]]);
    			fb[i][0]=abs(h[na[i]]-h[nb[na[i]]]);
    		}
    	for(j=1;j<=19;j++)
    		for(i=1;i<=n;i++)
    		{
    			g[i][j]=g[g[i][j-1]][j-1];
    			fa[i][j]=fa[i][j-1]+fa[g[i][j-1]][j-1];
    			fb[i][j]=fb[i][j-1]+fb[g[i][j-1]][j-1];
    		}
    	int k;
    	ll x0;
    	scanf("%lld",&x0);
    	p ans;
    	ans.x=-1;
    	for(i=1;i<=n;i++)
    	{
    		ll sa=0,sb=0;
    		j=i;
    		ll s=0;
    		for(k=19;k>=0;k--)
    			if(fa[j][k]+fb[j][k]+s<=x0)
    			{
    				s+=fa[j][k]+fb[j][k];
    				sa+=fa[j][k];
    				sb+=fb[j][k];
    				j=g[j][k];
    			}
    		if(na[j]!=-1&&s+abs(h[j]-h[na[j]])<=x0)
    			sa+=abs(h[j]-h[na[j]]);
    		double si;
    		if(!sb)
    			si=inf;
    		else
    			si=double(sa)/sb;
    		if(ans.x==-1||si<ans.s||(si==ans.s&&h[i]>h[ans.x]))
    		{
    			ans.x=i;
    			ans.s=si;
    		}
    	}
    	printf("%d
    ",ans.x);
    	int m;
    	scanf("%d",&m);
    	for(i=1;i<=m;i++)
    	{
    		int x;
    		ll x0;
    		scanf("%d%lld",&x,&x0);
    		j=x;
    		ll s=0;
    		ll sa=0,sb=0;
    		for(k=19;k>=0;k--)
    			if(fa[j][k]+fb[j][k]+s<=x0)
    			{
    				s+=fa[j][k]+fb[j][k];
    				sa+=fa[j][k];
    				sb+=fb[j][k];
    				j=g[j][k];
    			}
    		if(na[j]!=-1&&s+abs(h[j]-h[na[j]])<=x0)
    			sa+=abs(h[j]-h[na[j]]);
    		printf("%lld %lld
    ",sa,sb);
    	}
    	return 0;
    }
    
  • 相关阅读:
    【转载】在Linux中使用VS Code编译调试C++项目
    【转载】Visual Studio 2015 for Linux更好地支持Linux下的开发
    【转载】ODBC, OLEDB, ADO, ADO.Net的演化简史
    【转载】OLE DB, ADO, ODBC关系与区别
    【转载】ADO,OLEDB,ODBC,DAO的区别
    【转载】Linux系统启动流程
    91. Decode Ways
    90. Subsets II
    89. Gray Code
    88. Merge Sorted Array
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8513099.html
Copyright © 2011-2022 走看看