CF1937D Pinball 题解

题目链接:https://codeforces.com/contest/1937/problem/D

题意简述
一个长为n的格子,用 '<'或'>'组成的字符串表示,在位置i放一个小球,当前所在位置是'<'则下一秒左移一步,否则下一秒右移一步。小球移动后,之前位置的符号反转,'<'变成'>','>'变成'<',直到小球离开整个格子。
求在0至n-1共n个位置放置小球后离开格子需要的时间,每个位置放入小球互相独立,即都是放入初始状态的格子中。

题解

  1. 首先我们要明确小球是必定可以离开整个格子的,无论小球往左还是往右走,直到遇到一个方向相反的字符,小球调转方向,此时符号反转,即小球遇到的符号最终都是向格子外,直到小球离开;

  2. 我们考虑单独放一个小球到位置i,小球会从什么方向离开,如果当前的符号是'<',则小球先向左走,直到遇到一个反向的符号'>',此时小球转向,向右走,遇到之前的'<',再弹回来;模拟这个过程,除了s[i]外(从s[i]移到到s[i - 1]后,s[i]已经变成了'>'),如果左边有m个'>',则右边也需要m个'<'把小球弹回来,小球最终才是往左边离开;

  3. 我们考虑单独放一个小球到位置i,当前的符号是'<',左边有m个'>',右边有m个'<'(多于k个没有意义),最终小球离开时,需要多少秒。
    首先,小球从i一直向左直到离开,如果没有阻碍,时间是i + 1;
    如果有一对'>'和'<',记他们的位置为j和k,到j时,会转向,直到k再转向回到j,然后继续向左,此时多走的距离为(k - j) * 2;
    所以单独考虑位置i,答案就是i + 1 + 左右m对'>'和'<'的距离差的和 * 2;

  4. 从特殊到一般,我们考虑答案从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)\)

至此,我们可以先记录'<'的位置到数组中,然后从0到n - 1遍历计算所有小球会向左边离开的位置的答案,如果'<'位置数组为空则中止;至于小球向右边离开的答案,反向再来一次就行,我觉得应该可以一次遍历同时计算完成左右两种情况,这里等一位巨佬出手。

整体时间复杂度:\(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()
posted @   醉里挑燈看劍  阅读(121)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示