• 开车旅行(NOIP2012)


    原题传送门

    这道坑爹题调了我2小时233~

    首先这道题可以用set,平衡树,双向链表等一堆非(sang)常(xin)简(bing)单(kuang)的算法搞出对于任何一个高度h[i]的前2名和后2名

    然后我们看到这个

    就想到了倍增。。。

    但是调不出来o(≧口≦)o

    还要特判一下A走后B就不走了的情况。。(用va[i][0]表示)

    然后第一问O(N)。。第二问O(M)

    最后在黄学长的blog的帮助之下才调了出来。。

    真是zxyer说的纯模拟大水比题目啊(233~)

    简直跟A*八数码有的一拼。。

    下面贴代码

    #include<iostream>
    #include<set>
    #include<map>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define inf 5000000000LL
    using namespace std;
    int h[100005];
    int fa[100005],fb[100005];
    long long a[100005],b[100005],va[100005][17],vb[100005][17],to[100005][17];
    int n,m;
    struct data{
    	long long key,h;
    }t[5];
    
    inline bool operator<(data a,data b)
    {
        return a.key<b.key||(a.key==b.key&&a.h<b.h);
    }
    set <long long> q;
    map <long long,int> mp;
    void pre(){
    	for(int i=n;i;i--)
    	{
    		q.insert(h[i]);
    		t[1].h=*--q.lower_bound(h[i]);t[2].h=*q.upper_bound(h[i]);
    		if(t[1].h!=-inf)t[3].h=*--q.lower_bound(t[1].h);
    		else t[3].h=-inf;
    		if(t[2].h!=inf)t[4].h=*q.upper_bound(t[2].h);
    		else t[4].h=inf;
    		for(int k=1;k<=4;k++)
    			t[k].key=abs(t[k].h-h[i]);
    		sort(t+1,t+5);
    		a[i]=t[2].key;fa[i]=mp[t[2].h];
    		b[i]=t[1].key;fb[i]=mp[t[1].h];
    		for(int j=0;j<=16;j++)
    			if(j==0)
    			{
    				if(fa[i]){va[i][0]=a[i];to[i][0]=fa[i];}
    			}
    			else if(j==1) 
    			{
    				if(fb[fa[i]]){va[i][1]=a[i];vb[i][1]=b[fa[i]];to[i][1]=fb[fa[i]];}
    			}	
    		else 
    		if(to[to[i][j-1]][j-1])
    		{
    			va[i][j]=va[i][j-1]+va[to[i][j-1]][j-1];
    			vb[i][j]=vb[i][j-1]+vb[to[i][j-1]][j-1];
    			to[i][j]=to[to[i][j-1]][j-1];
    		}
    		else break;
    	}
    }
    double cal1(int x,int val)
    {
    	int t1=0,t2=0;
    	for(int i=16;i>=0;i--)
    		if(to[x][i]&&t1+va[x][i]+vb[x][i]+t2<=val)
    		{
    			t1+=va[x][i];t2+=vb[x][i];
    			x=to[x][i];
    		}
    	if(t2==0)return inf;
    	return (double)t1/(double)t2;
    }
    void cal2(int x,int val)
    {
    	int t1=0,t2=0;
    	for(int i=16;i>=0;i--)
    	if(to[x][i]&&t1+va[x][i]+vb[x][i]+t2<=val)
    	{
    		t1+=va[x][i];
    		t2+=vb[x][i];
    		x=to[x][i];
    	}
    	printf("%d %d
    ",t1,t2);
    }
    void solve1(){
    	double mn=1e60;int ans;
    	int num;
    	scanf("%d",&num);
    	for(int i=1;i<=n;i++)
    	{
    		double t=cal1(i,num);
    		if(t<mn||t==mn&&h[i]>h[ans])
    		{
    			mn=t;
    			ans=i;
    		}
    	}
    	printf("%d
    ",ans);
    }
    void solve2(){
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++)
    	{
    	int s,x;
    	scanf("%d%d",&s,&x);
    	cal2(s,x);
    	}
    }
    int main(){
    	scanf("%d",&n);
    	q.insert(-inf);q.insert(inf);
    	for(int i=1;i<=n;i++)
    	{
    	scanf("%d",&h[i]);
    	mp[h[i]]=i;
    	}
    	pre();
    	solve1();
    	solve2();
    	return 0;
    }
    

      

  • 相关阅读:
    小白学Python第二周小结(函数)
    小白学Python读写文件和处理异常
    小白学Python做个小游戏
    小白学Python第二周小结(字符串和常用数据结构)
    小白学Python第一周小结
    OpenGL进阶之Instancing
    加减乘除算法代码 31
    软件团队模式选择 31
    开发流程选择 31
    countdown(倒计时) 31
  • 原文地址:https://www.cnblogs.com/ghostfly233/p/6830990.html
Copyright © 2020-2023  润新知