Codeforces Round 930 (Div. 2) D. Pinball(思维 推公式)VP

文章描述了一个问题,关于在一个由<和>符号组成的格子中,小球根据初始位置的符号移动并反转相邻符号的过程,目标是计算每个位置放置小球后小球离开格子所需的时间。文章提供了四种情况的分析和代码实现,涉及字符串处理和动态规划的思想。
摘要由CSDN通过智能技术生成

题目大概意思:

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

思路:

我们放一个小球到位置i,如果当前的符号是'<',则小球先向左走,直到遇到一个反向的符号'>',此时小球转向,向右走,遇到下一个'<'(初始位置的'<'已经变成‘>’),再弹回来。

模拟这个过程我们会发现如果初始位置的左边有m个'>',则右边也需要m个'<'把小球弹回来,小球最终才是往左边离开。

所以我们讨论的就是初始位置左右‘<’和'>'的情况:

我们可以分成四种情况进行讨论:

一:初始位置为'<',小球从左侧出去。

我们不难发现上图的结果为 i + (r1 - l1) * 2 + (r2 - l2) * 2;我们可以推出公式 i + (∑ri - ∑li) * 2;

二:初始位置为'>',小球从左边出去

这时候计算的方法和一一样,但是当前位的‘>’也算一个li。

另外两种情况我们可以把字符串反转一下,再把<改成>,就可以上上述的两种来跑答案了

但要注意的是这时候的 i 表示的是第 n - i + 1位。

下面就是代码实现。我写的不太精简,大家也可以试试自己优化一下。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define edl '\n'
const int N = 1e6 + 10;
ll MAX = 0x3f3f3f3f3f3f3f3fll;
ll MIN = -MAX;

ll n, m;

string s;

ll ans[N];

void ck()
{
    ll l = 0;
    ll suml, sumr;
    ll cntl, cntr;
    suml = sumr = 0;
    cntl = cntr = 0;
    for (int i = 1; i <= n; i++)
    {
        if (l < i) l = i;
        if (s[i] == '<')
        {
            if (cntr) sumr -= i, cntr--;
            while (cntl > cntr && l <= n) if (s[++l] == '<') sumr += l, cntr++;
            if (cntl != cntr) break;
            ans[i] = min((sumr - suml) * 2 + i, ans[i]);
        }
        else
        {
            cntl++;
            suml += i;
        }
    }
    l = 0;
    suml = sumr = 0;
    cntl = cntr = 0;
    for (int i = 1; i <= n; i++)
    {
        if (l < i) l = i;
        if (s[i] == '>')
        {
            cntl++;
            suml += i;
            while (cntl > cntr && l <= n) if (s[++l] == '<') sumr += l, cntr++;
            if (cntl != cntr) break;
            ans[i] = min((sumr - suml) * 2 + i, ans[i]);
        }
        else if (cntr) cntr--, sumr -= i;
    }
}

void ck1()
{
    ll l = 0;
    ll suml, sumr;
    ll cntl, cntr;
    suml = sumr = 0;
    cntl = cntr = 0;
    for (int i = 1; i <= n; i++)
    {
        if (l < i) l = i;
        if (s[i] == '<')
        {
            if (cntr) sumr -= i, cntr--;
            while (cntl > cntr && l <= n) if (s[++l] == '<') sumr += l, cntr++;
            if (cntl != cntr) break;
            ans[n - i + 1] = min((sumr - suml) * 2 + i, ans[n - i + 1]);
        }
        else
        {
            cntl++;
            suml += i;
        }
    }
    l = 0;
    suml = sumr = 0;
    cntl = cntr = 0;
    for (int i = 1; i <= n; i++)
    {
        if (l < i)
            l = i;
        if (s[i] == '>')
        {
            cntl++;
            suml += i;
            while (cntl > cntr && l <= n) if (s[++l] == '<') sumr += l, cntr++;
            if (cntl != cntr) break;
            ans[n - i + 1] = min((sumr - suml) * 2 + i, ans[n - i + 1]);
        }
        else if (cntr) cntr--, sumr -= i;
    }
}

void Solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++) ans[i] = MAX;
    cin >> s;
    s = " " + s;
    ck();
    for (int i = 1; i <= n; i++)
        if (s[i] == '<') s[i] = '>';
        else s[i] = '<';
    for (int i = 1; i <= n / 2; i++) swap(s[i], s[n - i + 1]);
    ck1();
    for (int i = 1; i <= n; i++) cout << ans[i] << " ";
    cout << edl;
}

int main()
{
    std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    ll t = 1;
    cin >> t;
    while (t--)
        Solve();

    return 0;
}

链接:Problem - D - Codeforces

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值