D. Pinball

D. Pinball

There is a one-dimensional grid of length $n$. The $i$-th cell of the grid contains a character $s_i$, which is either '<' or '>'.

When a pinball is placed on one of the cells, it moves according to the following rules:

  • If the pinball is on the $i$-th cell and $s_i$ is '<', the pinball moves one cell to the left in the next second. If $s_i$ is '>', it moves one cell to the right.
  • After the pinball has moved, the character $s_i$ is inverted (i. e. if $s_i$ used to be '<', it becomes '>', and vice versa).
  • The pinball stops moving when it leaves the grid: either from the left border or from the right one.

You need to answer $n$ independent queries. In the $i$-th query, a pinball will be placed on the $i$-th cell. Note that we always place a pinball on the initial grid.

For each query, calculate how many seconds it takes the pinball to leave the grid. It can be shown that the pinball will always leave the grid within a finite number of steps.

Input

Each test contains multiple test cases. The first line contains the number of test cases $t$ ($1 \le t \le 10^5$). The description of the test cases follows.

The first line of each test case contains an integer $n$ ($1 \le n \le 5 \cdot 10^5$).

The second line of each test case contains a string $s_1s_2 \ldots s_{n}$ of length $n$ consisting of characters '<' and '>'.

It is guaranteed that the sum of $n$ over all test cases does not exceed $5 \cdot 10^5$.

Output

For each test case, for each $i$ ($1 \le i \le n$) output the answer if a pinball is initially placed on the $i$-th cell.

Example

input

3
3
><<
4
<<<<
6
<><<<>

output

3 6 5 
1 2 3 4 
1 4 7 10 8 1 

Note

In the first test case, the movement of the pinball for $i=1$ is shown in the following pictures. It takes the pinball $3$ seconds to leave the grid.

The movement of the pinball for $i=2$ is shown in the following pictures. It takes the pinball $6$ seconds to leave the grid.

 

解题思路

  唉唉,比赛刚结束 $2$ 分钟就调出来 AC 了。(ノToT)ノ ~┻┻

  模拟一下样例就会发现整个过程其实就是在反复横跳,直到最后到达左右边界结束。不管初始时的 $s_i$ 是 < 还是 >,当向左移动遇到 > 或者向右移动遇到 < 都会改变移动方向。所以我们关心的是在整个移动的过程中,会经过 $i$ 左边哪些 > 以及 $i$ 右边哪些 <

  为此我们可以先把所有 < 的下标按顺序存到数组 $l$ 中,假设有 $cl$ 个。同理把所有 > 的下标按顺序存到数组 $r$ 中,假设有 $cr$ 个。那么对于第 $i$ 个询问,就可以在 $l$ 中二分出小于 $i$ 的最大下标,假设是 $l$ 中的第 $x$ 个元素。同理在 $r$ 中二分出大于 $i$ 的最小下标,假设是 $r$ 中的第 $y$ 个元素。此时左边有 $x$ 个 >,右边有 $cl-y+1$ 个 <。然后分类讨论。

  如果 $s_i$ 是 <,模拟一下就会发现当 $x \leq cl-y+1$ 时最后会走到左边界,左边会经过 $r[1, x]$ 中的 >,右边会经过 $l[y, y+x-1]$ 中的 <,考虑如何快速计算中间经过的路程,参考下图:

  经过的路程就是 $(7-4) + (8-4) + (8-2) + (10 - 2) + (10 - 0)$,等价于 $7 + 2 \cdot ((8 + 10) - (2 + 4))$。从而推出更一般的情况:$i + 2 \cdot \left(\sum\limits_{i=y}^{y+x-1}{l_i} - \sum\limits_{i=1}^{x}{r_i}\right)$,因此可对 $l$ 和 $r$ 预处理前缀和来加速计算。

  同理分析 $x > cl-y+1$ 的情况,最后会走到右边界,左边会经过 $r[x-(cl-y+1), x]$ 中的 >,右边会经过 $l[y, cl]$ 中的 <,参考下图:

  经过的路程就是 $(7-4) + (8-4) + (8-2) + (12 - 2)$,等价于 $7 + 12 + 2 \cdot ((8) - (2 + 4))$。从而推出更一般的情况:$i + n + 1 + 2 \cdot \left(\sum\limits_{i=y}^{cl}{l_i} - \sum\limits_{i=x-(cl-y+1)}^{x}{r_i}\right)$。

  $s_i$ 是 > 的情况也十分类似,当 $x \geq cl-y+1$ 时最后会走到右边界,左边会经过 $r[x-(cl-y+1)+1, x]$ 中的 >,右边会经过 $l[y, cl]$ 中的 <,参考下图:

  经过的路程就是 $-i + n + 1 + 2 \cdot \left(\sum\limits_{i=y}^{cl}{l_i} - \sum\limits_{i=x-(cl-y+1)+1}^{x}{r_i}\right)$。

  同理分析 $x < cl-y+1$ 的情况,最后会走到左边界,左边会经过 $r[1, x]$ 中的 >,右边会经过 $l[y, y+x]$ 中的 <,参考下图:

  经过的路程就是 $-i + 2 \cdot \left(\sum\limits_{i=y}^{y+x}{l_i} - \sum\limits_{i=1}^{x}{r_i}\right)$。

  AC 代码如下,时间复杂度为 $O(n \log{n})$:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 5e5 + 10;

char s[N];
int l[N], r[N];
LL sl[N], sr[N];

void solve() {
    int n;
    scanf("%d %s", &n, s + 1);
    int cl = 0, cr = 0;
    for (int i = 1; i <= n; i++) {
        if (s[i] == '<') l[++cl] = i;
        else r[++cr] = i;
    }
    for (int i = 1; i <= cl; i++) {
        sl[i] = sl[i - 1] + l[i];
    }
    for (int i = 1; i <= cr; i++) {
        sr[i] = sr[i - 1] + r[i];
    }
    for (int i = 1; i <= n; i++) {
        int x = prev(lower_bound(r + 1, r + cr + 1, i)) - r;
        int y = upper_bound(l + 1, l + cl + 1, i) - l;
        if (s[i] == '<') {
            if (x <= cl - y + 1) printf("%lld ", i + 2 * (sl[y + x - 1] - sl[y - 1] - sr[x]));
            else printf("%lld ", i + n + 1 + 2 * (sl[cl] - sl[y - 1] - (sr[x] - sr[x - (cl - y + 2)])));
        }
        else {
            if (x >= cl - y + 1) printf("%lld ", -i + n + 1 + 2 * (sl[cl] - sl[y - 1] - (sr[x] - sr[x - (cl - y + 1)])));
            else printf("%lld ", -i + 2 * (sl[y + x] - sl[y - 1] - sr[x]));
        }
    }
    printf("\n");
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        solve();
    }
    
    return 0;
}

 

参考资料

  Codeforces Round 930 (Div. 1, Div. 2) Editorial:https://codeforces.com/blog/entry/126513

posted @ 2024-03-01 16:20  onlyblues  阅读(7)  评论(0编辑  收藏  举报
Web Analytics