CF EDU 133 C - Robot in a Hallway

st表 or 后缀和 优化dp

C - Robot in a Hallway

题意

有一个两行 n 列的网格,每个格子有一个解锁时间 \(a[i][j]\) (注意这个是解锁的时间,最早到达该点的时间要 + 1), 过了这个时间才能走进这个格子。每秒可以选择上下左右移一格或者不动,求从 (0, 0) 出发恰好每个格子走一次的最短时间

思路

只有三种可能

1660376122867

1660376292251

  1. 1660376580246

可预处理出走蛇形走到 (i, j) 的时间 \(h[i][j]\)

走蓝线的时间为 走蓝线区间不停顿的时间 - 在某个格子等待的最长时间

以图 3 为例,可以给格子按

1660376506426

标号 id

设走到 \((i-1,j)\) 后之后都按 3 的蓝线走,则蓝线时间为

\(id[i][0]-id[i-1][1]+max(0,a[k][j]-(h[i-1][1]+id[k][j]-id[i-1][1]))\)

所以用 st 表维护 \(a[k][j]-id[k][j]\) 的最大值即可 (也可预处理出上下两行的后缀和,复杂度会少一个log)

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"

typedef long long ll;
typedef pair<int, int> PII;

const int N = 4e5 + 10, M = 20;

int h[N][2], a[N][2];
int id[N][2];
int n;
void presolve()
{
	h[0][0] = 0;
	for (int k = 1; k < 2 * n; k++)
	{
		int i = k / 2;
		if (k % 4 == 0)
			h[i][0] = max(h[i-1][0] + 1, a[i][0]);
		else if (k % 4 == 1)
			h[i][1] = max(h[i][0] + 1, a[i][1]);
		else if (k % 4 == 2)
			h[i][1] = max(h[i-1][1] + 1, a[i][1]);
		else
			h[i][0] = max(h[i][1] + 1, a[i][0]);
	}
}
int hs(int idx, int op)
{
	int i, j;
	if (op == 0)
	{
		j = idx / n;
		if (j == 0)
			i = idx;
		else
			i = 2 * n - 1 - idx;
	}
	else
	{
		j = (idx / n) ^ 1;
		if (j == 1)
			i = idx;
		else
			i = 2 * n - 1 - idx;
	}
	return a[i][j] - id[i][j];
}

template<typename T> struct ST
{
    ST(int n, int op)
    {
        siz = n;
        maxv.resize(n+1);
        int t = __lg(n) + 1;
        for(int i=0;i<n;i++) maxv[i].resize(t);
        
        for(int i = 0; i < n; i++) maxv[i][0] = hs(i, op);
        for(int j = 1; j < t; j++) 
            for(int i = 0; i < n - (1<<j)+1; i++)
                maxv[i][j] = max(maxv[i][j-1], maxv[i+(1 << (j-1))][j-1]);
    }
    T getmax(int l,int r)
	{
	    int k = __lg(r-l+1);
	    return max(maxv[l][k],maxv[r-(1<<k)+1][k]);
    }      
private:
    int siz = 0;
    vector<vector<T>> maxv;
};

int solve(int op)
{
	for (int i = 0; i < n; i++)
	{
		id[i][op] = i;
		id[i][op^1] = 2 * n - 1 - i;
	}
	ST<int> s(2*n, op);
	int ans;
	if (op == 0)
		ans = 2 * n - 1 + max(0, s.getmax(1, 2 * n - 1));
	else
		ans = 2e9;
	int first = op ? 1 : 2;
	for (int i = first; i < n; i += 2)
	{
		int l = i, r = 2 * n - i - 1;
		int now = h[i-1][op] + id[i][op^1] - id[i-1][op] + max(0, s.getmax(l, r) + id[i-1][op] - h[i-1][op]);
		ans = min(ans, now);
	}
	return ans;
}
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int T;
	cin >> T;
	while(T--)
	{
		cin >> n;
		for (int j = 0; j < 2; j++)
		{
			for (int i = 0; i < n; i++)
			{
				int x;
				cin >> x;
				a[i][j] = x + 1;
			}
		}
		a[0][0] = 0;
		presolve();
		int ans = min(solve(0), solve(1));
		cout << ans << endl;
	}
    return 0;
}
posted @ 2022-08-13 15:49  hzy0227  阅读(62)  评论(0编辑  收藏  举报