CodeForces 733E Sleep in Class

原题


题意:给N个台阶 每个台阶有一个字母 U代表上 D代表下 每个台阶走过一次就会转换,U换成D,D换成U。输出从第N个台阶走出去的步数。以样例中的3为例,就是UUD到UUU到UDU到UDD此时已经走出去了。

题解:我们可以写写画画,然后找到规律,对于当前位置,如果左边的U小于右边包括本身的D的个数,那么最后一定从左边出去,反之从右边出去。至于其他的步数,其实就是(左边的U到当前位置的距离 + 右边的D到当前位置的距离)* 2,然后左边U的个数和右边D的个数取MIN(左边U的个数,右边D的个数),这里面两个都包括自己。

举个例子 对于6 ,个数就是MIN(2,1) = 1, 然后就是左边1个U的距离1 * 2 + 右边一个D的距离1 * 2 = 4, 在加上从右边出去的距离(4 - 2), 答案就是6;

代码:

#include <bits/stdc++.h>
#define mem(a, b) memset(a, b, sizeof(a))
using namespace std;

int n, num[1000005];
__int64 ans[1000005], sumu[1000005], sumd[1000005];
char ch[1000005];

int main()
{
    mem(ans, 0);
    scanf("%d", &n);
    scanf("%s", ch + 1);
    sumu[0] = 0;
    for(int i = 1;i <= n;i++)
    {
        if(ch[i] == 'U')
            sumu[i] = sumu[i - 1] + 1;
        else
            sumu[i] = sumu[i - 1];
    }
    sumd[n + 1] = 0;
    for(int i = n;i >= 1;i--)
    {
        if(ch[i] == 'D')
            sumd[i] = sumd[i + 1] + 1;
        else
            sumd[i] = sumd[i + 1];
    }
    __int64 w = 0, l = 0, r = 0;
    for(int i = 1;i <= n;i++)
    {
        if(r > l)
            w += (r - l);
        __int64 ll = min(sumu[i], sumd[i]);
        if(r - l > ll)
        {
            while(r - l > ll)
            {
                __int64 pos = num[l + 1];
                w -= (__int64)(i - pos);
                l++;
            }
        }
        ans[i] += 2 * w;
        if(sumu[i - 1] < sumd[i])
            ans[i] += (__int64)i;
        if(ch[i] == 'U')
            num[++r] = i;
    }
    w = 0, l = 0, r = 0;
    for(int i = n;i >= 1;i--)
    {
        if(r > l)
           w += (r - l);
        __int64 ll = min(sumu[i], sumd[i]);
        if(r - l > ll)
        {
            while(r - l > ll)
            {
                int pos = num[l + 1];
                w -= (__int64)(pos - i);
                l++;
            }
        }
        ans[i] += 2 * w;
        if(sumu[i - 1] >= sumd[i])
            ans[i] += (__int64)n - (__int64)i + 1;
        if(ch[i] == 'D')
            num[++r] = i;
    }
    for(int i = 1;i <= n;i++)
        printf("%I64d ", ans[i]);
    printf("\n");
    return 0;
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值