• 【Luogu P1081】[NOIP2012 提高组] 开车旅行


    链接:

    洛谷

    题目大意:

    小 A、小 B 从左往右走,小 A 会走差值次小高度,小 B 走差值最小高度。

    给定总路程限制,求出两人路程最小比。

    给定起点和限制,求两人路程。

    正文:

    在做题时会冒出一个想法:可能要先预处理出所有位置的下一个位置。很明显,这是解决本题的“先行官”。

    我们可以通过链表,对它排序后,把前后指针指向 (i+1,i-1)。然后判断大小得到小 A、小 B 的下一位置,每操作一次,就将当前节点删掉,以免后面节点误选此节点。

    我们求出了两人的下一位置 ( ext{Ato}_i, ext{Bto}_i)

    ( ext{disA}_{i,j,k}, ext{disB}_{i,j,k}quad(kin[0,1])) 分别表示在 (i) 节点处小 A/小 B 跑了 (2^j) 步时小 A 的总距离和在 (i) 节点处小 A/小 B 跑了 (2^j) 步时小 B 的总距离。

    还需设 (f_{i,j,k}) 表示在 (i) 节点处小 A/小 B 跑了 (2^j) 步时的位置。

    显然有:

    [egin{aligned} f_{i,j,k} &= left{egin{matrix} ext{Ato}_i & (j=0,k=0)\ ext{Bto}_i & (j=0,k=1)\ f_{f_{i,j-1,k},j-1,koplus1} & (i=1)\ f_{f_{i,j-1,k},j-1,k} & (i>1) end{matrix} ight. \ ext{disA}_{i,j,k} &= left{egin{matrix} |h_i-h_{ ext{Ato}_i}| & (j=0,k=0)\ 0 & (j=0,k=1)\ ext{disA}_{i,j-1,k}+ ext{disA}_{f_{i,j-1,k},j-1,koplus1} & (i=1)\ ext{disA}_{i,j-1,k}+ ext{disA}_{f_{i,j-1,k},j-1,k} & (i>1)\ end{matrix} ight. \ ext{disB}_{i,j,k} &= left{egin{matrix} 0 & (j=0,k=0)\ |h_i-h_{ ext{Bto}_i}| & (j=0,k=1)\ ext{disB}_{i,j-1,k}+ ext{disB}_{f_{i,j-1,k},j-1,koplus1} & (i=1)\ ext{disB}_{i,j-1,k}+ ext{disB}_{f_{i,j-1,k},j-1,k} & (i>1)\ end{matrix} ight. end{aligned}]

    求完后倍增跑从 (s) 出发的两人路程即可。

    代码:

    
    const int N = 1e5 + 5;
    
    inline ll Read()
    {
    	ll x = 0, f = 1;
    	char c = getchar();
    	while (c != '-' && (c < '0' || c > '9')) c = getchar();
    	if (c == '-') f = -f, c = getchar();
    	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
    	return x * f;
    }
    
    int n, m;
    int pos[N], Ato[N], Bto[N];
    struct node
    {
    	int id, pre, nxt;
    	ll val;
    	bool operator < (const node &a) const
    	{
    		return val < a.val;
    	}
    	node() {}
    	node (int i, ll v) {id = i, val = v;} 
    }h[N];
    
    int Choose(int i, int a, int b)
    {
    	if (!a) return h[b].id;
    	if (!b) return h[a].id;
    	if (h[i].val - h[a].val <= h[b].val - h[i].val)
    		return h[a].id;
    	else return h[b].id;
    }
    
    void Delete(int p)
    {
    	if (h[p].pre) h[h[p].pre].nxt = h[p].nxt; 
    	if (h[p].nxt) h[h[p].nxt].pre = h[p].pre;
    }
    
    void Prework()
    {
    	sort (h + 1, h + 1 + n);
    	for (int i = 1; i <= n; i++)
    	{
    		pos[h[i].id] = i;
    		h[i].pre = i - 1;
    		h[i].nxt = i + 1;
    	}
    	h[1].pre = h[n].nxt = 0;
    	for (int i = 1; i < n; i++)
    	{
    		int p = pos[i], p1 = h[p].pre, p2 = h[p].nxt;
    		if (p1 && (h[p].val - h[p1].val <= h[p2].val - h[p].val || !p2))
    			Bto[i] = h[p1].id, Ato[i] = Choose(p, h[p1].pre, p2);
    		else
    			Bto[i] = h[p2].id, Ato[i] = Choose(p, p1, h[p2].nxt);
    		Delete(p);
    	}
    } 
    
    ll disA[N][30][2], disB[N][30][2], tmpA, tmpB, Log;
    int f[N][30][2];
    
    void Solve(int s, ll x)
    {
    	tmpA = tmpB = 0; int k = 0;
    	for (int j = Log; ~j; j--)
    		if (f[s][j][k] && disA[s][j][k] + disB[s][j][k] <= x)
    		{
    			x -= disA[s][j][k] + disB[s][j][k];
    			tmpA += disA[s][j][k], tmpB += disB[s][j][k];
    			if(j == 0) k ^= 1;
    			s = f[s][j][k];
    		}
    }
    
    int main()
    {
    	n = Read();
    	for (int i = 1; i <= n; i++)
    		h[i] = node(i, Read());
    	
    	Prework();
    	
    	for (int i = 1; i <= n; i++)
    	{
    		if (Ato[i])
    			f[i][0][0] = Ato[i],
    			disA[i][0][0] = abs(h[pos[i]].val - h[pos[Ato[i]]].val);
    		if (Bto[i])
    			f[i][0][1] = Bto[i],
    			disB[i][0][1] = abs(h[pos[i]].val - h[pos[Bto[i]]].val);
    	}
    	Log = log2(n) + 1;
    	for (int j = 1; j <= Log; j++)
    		for (int i = 1; i <= n; i++)
    			for (int k = 0; k <= 1; k++)
    			{
    				if(f[i][j - 1][k]) f[i][j][k] = f[f[i][j - 1][k]][j - 1][j == 1? 1 ^ k: k];
    				if(f[i][j][k]) disA[i][j][k] = disA[i][j - 1][k] + disA[f[i][j - 1][k]][j - 1][j == 1? 1 ^ k: k],
    				               disB[i][j][k] = disB[i][j - 1][k] + disB[f[i][j - 1][k]][j - 1][j == 1? 1 ^ k: k];
    			}
    	ll s, x = Read(), ansA = 1, ansB = 0, id = 0;
    	for (int i = 1; i <= n; i++)
    	{
    		Solve(i, x);
    		if (!tmpB) tmpA = 1;
    		if (tmpA * ansB < tmpB * ansA || (tmpA * ansB == tmpB * ansB && h[pos[i]].val > h[pos[id]].val))
    			ansA = tmpA, ansB = tmpB, id = i;
    	}
    	printf ("%lld
    ", id);
    	for (m = Read(); m--; )
    	{
    		s = Read(), x = Read();
    		Solve(s, x);
    		printf ("%lld %lld
    ", tmpA, tmpB);
    	}
    	return 0;
    }
    
  • 相关阅读:
    学而201205期先导班信息系统项目管理师招生简章
    201205期蘑菇班信息系统项目管理师招生简章
    用常识驳倒方舟子之一 :韩寒的女儿与常识
    学而201211期蘑菇班信息系统项目管理师招生简章
    工作量与工作历时计算
    git设置中英文
    楼层跳转scrollintoview坑
    一则浏览器兼容性解决案例(搜狗)
    C语言未初始化变量输出的是随即数
    远程关机,在MM面前显摆一次的机会,别错过 To Phper
  • 原文地址:https://www.cnblogs.com/GJY-JURUO/p/14879952.html
Copyright © 2020-2023  润新知