• NOIP 2012 开车旅行


    https://loj.ac/problem/2604

    题目

    两个人开车,A向后选择距离第二小的城市,B向后选择距离最小的城市,A先开,两个人轮流开一次,当达不到要求或者长度超过x以后就不开了

    1:输入x0,求A开的距离与B开的距离比值最小时,出发的城市是什么(B的距离为0时视为正无穷,正无穷相等)

    2:输入一系列x和出发城市,问A开了多长距离,B开了多长距离

    城市有$10^5$个,两个城市之间的距离小于等于$2 imes10^9$,$xleqslant 10^9$

    题解

    如果不管数据范围,很容易设da[s][l][x]为从s出发,开了l次,第一次是x开的,A开的距离,同理设db[s][l][x]

    然后很容易转移,最后O(n)循环找出符合条件的次数

    然而这个l就超了,连状态都无法保存

    由于l是单调递增的,每次转移都增加1,因此可以改为倍增

    提前处理出开了$2^k$后到达的城市编号,然后设da[s][k][x]为从s出发,开了$2^k$次,第一次是x开的,A开的距离,同理设db[s][k][x]

    思维比较简单,但是写起来很容易写错

    AC代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<map>
    #define REP(i,a,b) for(register int i=(a); i<(b); i++)
    #define REPE(i,a,b) for(register int i=(a); i<=(b); i++)
    #define PERE(i,a,b) for(register int i=(a); i>=(b); i--)
    using namespace std;
    typedef long long ll;
    int n, m;
    struct node {
    	int hb, id;
    	bool operator<(const node &r) const {return hb<r.hb;}
    } cs[100007];
    struct pii {
    	int a,b;
    	bool operator<(const pii&r) const {
    		if(b==-1) return false;
    		return a<r.a || (a==r.a && cs[b].hb<cs[r.b].hb);
    	}
    };
    int goa[100007], gob[100007];
    int to[100007];
    int nxt[100007], prv[100007];
    inline void lk(int a, int b) {
    	if(~a) nxt[a]=b;
    	if(~b) prv[b]=a;
    }
    inline void gen() {
    	sort(cs,cs+n);
    	REP(i,0,n) to[cs[i].id]=i;
    	REP(i,0,n) nxt[i]=i+1;
    	REP(i,0,n) prv[i]=i-1;
    	nxt[n-1]=-1;
    	pii t[4], p;
    	REP(i,0,n-1) {
    		int now=to[i];
    		p.a=0x7f7f7f7f; p.b=-1;
    		int tn=0;
    		if(~prv[now]) {
    			p.a=cs[now].hb-cs[prv[now]].hb;
    			p.b=prv[now];
    			t[tn++]=p;
    			int now2=prv[now];
    			if(~prv[now2]) {
    				t[tn].a=cs[now].hb-cs[prv[now2]].hb;
    				t[tn].b=prv[now2];
    				tn++;
    			}
    		}
    		if(~nxt[now]) {
    			pii tmp;
    			tmp.a=cs[nxt[now]].hb-cs[now].hb;
    			tmp.b=nxt[now];
    			if(tmp<p) p=tmp;
    			t[tn++]=tmp;
    			int now2=nxt[now];
    			if(~nxt[now2]) {
    				t[tn].a=cs[nxt[now2]].hb-cs[now].hb;
    				t[tn].b=nxt[now2];
    				tn++;
    			}
    		}
    		gob[i]=cs[p.b].id;
    		if(tn>=2) {
    			sort(t,t+tn);
    			goa[i]=cs[t[1].b].id;
    		} else {
    			goa[i]=-1;
    		}
    		lk(prv[now], nxt[now]);
    	}
    	goa[n-1]=gob[n-1]=-1;
    }
    int x0, s[100007], x[int(1e5)+7]; //因为少写了个0错得很惨
    int f[100007][32][2];
    int da[100007][32][2], db[100007][32][2];
    inline void genf() {
    /*	f[i][2^0][0]=go[i];
    	f[i][2^0][1]=go2[i];
    	k=1 f[i][2^1][0]=f[f[i][2^0][0]][2^0][1];
    	k>1 f[i][2^k][0]=f[f[i][2^(k-1)][0]][2^(k-1)][0];*/
    	REP(i,0,n) f[i][0][0]=goa[i], f[i][0][1]=gob[i];
    	REP(i,0,n) {
    		if(~f[i][0][0]) f[i][1][0]=f[f[i][0][0]][0][1];
    		else f[i][1][0]=-1;
    		if(~f[i][0][1]) f[i][1][1]=f[f[i][0][1]][0][0];
    		else f[i][1][1]=-1;
    	}
    	REP(k,2,32) REP(i,0,n) {
    		if(~f[i][k-1][0]) f[i][k][0]=f[f[i][k-1][0]][k-1][0];
    		else f[i][k][0]=-1;
    		if(~f[i][k-1][1]) f[i][k][1]=f[f[i][k-1][1]][k-1][1];
    		else f[i][k][1]=-1;
    	}
    }
    inline void dp() {
    	REP(i,0,n) {
    		//其实-1不是特别有必要,因为只有可以到达才会使用dp
    		if(~goa[i]) da[i][0][0]=abs(cs[to[goa[i]]].hb-cs[to[i]].hb); else da[i][0][0]=-1;
    		da[i][0][1]=0;
    		db[i][0][0]=0;
    		if(~gob[i]) db[i][0][1]=abs(cs[to[gob[i]]].hb-cs[to[i]].hb); else db[i][0][1]=-1;
    	}
    	REP(i,0,n) {
    		da[i][1][0]=da[i][0][0];
    		if(~gob[i]) da[i][1][1]=da[gob[i]][0][0]; else da[i][1][1]=-1;
    		if(~goa[i]) db[i][1][0]=db[goa[i]][0][1]; else db[i][1][0]=-1;
    		db[i][1][1]=db[i][0][1];
    	}
    	REP(k,2,32) REP(i,0,n) {
    		if(~f[i][k-1][0]) {
    			da[i][k][0]=da[i][k-1][0]+da[f[i][k-1][0]][k-1][0];
    			db[i][k][0]=db[i][k-1][0]+db[f[i][k-1][0]][k-1][0];
    		} else da[i][k][0]=-1, db[i][k][0]=-1;
    
    		if(~f[i][k-1][1]) {
    			da[i][k][1]=da[i][k-1][1]+da[f[i][k-1][1]][k-1][1];
    			db[i][k][1]=db[i][k-1][1]+db[f[i][k-1][1]][k-1][1];
    		} else da[i][k][1]=-1, db[i][k][1]=-1;
    	}
    }
    void getd(int s, int l, int &a, int &b) {
    	int x=0; a=0, b=0;
    	
    	PERE(i,31,0) {
    		if(~f[s][i][x] && da[s][i][x]+db[s][i][x]<=l) {
    			l-=da[s][i][x]+db[s][i][x];
    			a+=da[s][i][x], b+=db[s][i][x];
    			s=f[s][i][x];
    		}
    	}
    }
    int main() {
    	scanf("%d", &n);
    	REP(i,0,n) scanf("%d", &cs[i].hb), cs[i].id=i;
    	scanf("%d", &x0);
    	scanf("%d", &m);
    	REP(i,0,m) scanf("%d%d", &s[i], &x[i]);
    
    	gen();
    	genf();
    	dp();
    	int aa=-1,bb=-1,ch=-1;
    	REP(i,0,n) {
    		int a,b;
    		getd(i,x0,a,b);
    
    		if(aa<0) {
    			aa=a,bb=b;
    			ch=i;
    		} else {
    			long long s1=(long long)a*bb, s2=(long long)aa*b;
    			if(s1<s2) {
    				aa=a, bb=b, ch=i;
    			}
    		}
    
    	}
    	printf("%d
    ", ch+1);
    	REP(i,0,m) {
    		int a,b; getd(s[i]-1, x[i], a, b);
    		printf("%d %d
    ", a, b);
    	}
    }
    
  • 相关阅读:
    远程管理登录Linux
    Linux常用命令之文件搜索命令
    PowerPoint笔记(七)
    PowerPoint笔记(六)
    C Primer Plus(四)
    Linux常用命令之文件处理命令
    Linux常用命令之权限管理命令
    C Primer Plus(五)
    C Primer Plus(六)
    C Primer Plus(三)
  • 原文地址:https://www.cnblogs.com/sahdsg/p/12527780.html
Copyright © 2020-2023  润新知