题目链接:https://codeforces.com/contest/1937/problem/D
题意简述
一个长为n的格子,用 '<'或'>'组成的字符串表示,在位置i放一个小球,当前所在位置是'<'则下一秒左移一步,否则下一秒右移一步。小球移动后,之前位置的符号反转,'<'变成'>','>'变成'<',直到小球离开整个格子。
求在0至n-1共n个位置放置小球后离开格子需要的时间,每个位置放入小球互相独立,即都是放入初始状态的格子中。
题解
-
首先我们要明确小球是必定可以离开整个格子的,无论小球往左还是往右走,直到遇到一个方向相反的字符,小球调转方向,此时符号反转,即小球遇到的符号最终都是向格子外,直到小球离开;
-
我们考虑单独放一个小球到位置i,小球会从什么方向离开,如果当前的符号是'<',则小球先向左走,直到遇到一个反向的符号'>',此时小球转向,向右走,遇到之前的'<',再弹回来;模拟这个过程,除了s[i]外(从s[i]移到到s[i - 1]后,s[i]已经变成了'>'),如果左边有m个'>',则右边也需要m个'<'把小球弹回来,小球最终才是往左边离开;
-
我们考虑单独放一个小球到位置i,当前的符号是'<',左边有m个'>',右边有m个'<'(多于k个没有意义),最终小球离开时,需要多少秒。
首先,小球从i一直向左直到离开,如果没有阻碍,时间是i + 1;
如果有一对'>'和'<',记他们的位置为j和k,到j时,会转向,直到k再转向回到j,然后继续向左,此时多走的距离为(k - j) * 2;
所以单独考虑位置i,答案就是左右m对'>'和'<'的距离差的和*2; -
从特殊到一般,我们考虑答案从i到i + 1的转移;
首先前提是小球放到位置i最终是向左离开的,需要的时间是i + 1 + more,more表示小球中间来回弹需要的时间;
此时小球放置到了原始的i + 1,如果s[i + 1] = '>',则右边需要多一个'<'弹回来,才等于在s[i]向左的时间;
这边我们需要一个等式,有四个变量\(a < b < c < d\),则\((c - b) + (d - a) = (c - a) + (d - b)\);
我们从s[i]转移到s[i + 1],more需要增加的就是下一个'<'的位置j减当前位置i的距离2;
如果s[i + 1]是'<'呢,假设前面已经有k个'>'相匹配了,由于小球从i + 1的位置开始,则匹配的'<'少了一个,需要右边再补一个'<',小球才会从左边离开,more需要增加的距离也是下一个'<'位置减i的距离2:
\((d - b) + (e - a) = (c - b) + (d - a) + (e - c)\)
至此,我们可以\(O(n)\)的计算所有小球会向左边离开的位置的答案,至于小球向右边离开的答案,反向再来一次就行,我觉得应该可以一次遍历同时计算完成左右两种情况,这里等一位巨佬出手。
Python代码
点击查看代码
import sys
# region fastio
input = lambda: sys.stdin.readline().rstrip()
sint = lambda: int(input())
mint = lambda: map(int, input().split())
ints = lambda: list(map(int, input().split()))
# endregion fastio
def solve() -> None:
n = sint()
s = input()
ans = [-1] * n
left, right = [], []
for i in range(n):
if s[i] == '>':
right.append(i)
else:
left.append(i)
left.reverse()
more = 0
for i in range(n):
if not left:
break
more += (left.pop() - i) * 2
ans[i] = i + 1 + more
more = 0
for i in range(n - 1, -1, -1):
if not right:
break
more += (i - right.pop()) * 2
ans[i] = n - i + more
print(*ans)
for _ in range(int(input())):
solve()