CF378E-Sleep in Class及378反思

Sleep in Class

Codeforces Round #378 (Div. 2) E.Sleep in Class

The academic year has just begun, but lessons and olympiads have already occupied all the free time. It is not a surprise that today Olga fell asleep on the Literature. She had a dream in which she was on a stairs.

The stairs consists of n steps. The steps are numbered from bottom to top, it means that the lowest step has number 1, and the highest step has number n. Above each of them there is a pointer with the direction (up or down) Olga should move from this step. As soon as Olga goes to the next step, the direction of the pointer (above the step she leaves) changes. It means that the direction “up” changes to “down”, the direction “down” — to the direction “up”.

Olga always moves to the next step in the direction which is shown on the pointer above the step.

If Olga moves beyond the stairs, she will fall and wake up. Moving beyond the stairs is a moving down from the first step or moving up from the last one (it means the n-th) step.

In one second Olga moves one step up or down according to the direction of the pointer which is located above the step on which Olga had been at the beginning of the second.

For each step find the duration of the dream if Olga was at this step at the beginning of the dream.

Olga’s fall also takes one second, so if she was on the first step and went down, she would wake up in the next second.

Input
The first line contains single integer n (1 ≤ n ≤ 10^6) — the number of steps on the stairs.

The second line contains a string s with the length n — it denotes the initial direction of pointers on the stairs. The i-th character of string s denotes the direction of the pointer above i-th step, and is either ‘U’ (it means that this pointer is directed up), or ‘D’ (it means this pointed is directed down).

The pointers are given in order from bottom to top.

Output
Print n numbers, the i-th of which is equal either to the duration of Olga’s dream or to  - 1 if Olga never goes beyond the stairs, if in the beginning of sleep she was on the i-th step.


题解

E题咋看真的没思路,比赛时也没做出来。其实这道题是完全在能力范围内的,还是我最擅长的前后缀和orz。
分析一个给定的字符串,我们可以发现一个特点:不存在转不出去的序列,也就是说,所有的位置都是有解的,-1这个输出完全是蒙人的。
然后可以看,既然所有位置都有解,我们可以观察一个位置是怎么走出去的,不难发现,对于一个‘U’来说,都是先向右走再向左走,这样走来走去最后走出去的。对于‘D’就反过来。这样来看,我们就可以发现一个解的轨迹只跟那些需要转头的点有关,或者说解只跟拐点相关。那么什么是拐点呢?对于一个特定的位置来说,容易想到在它左边的‘U’和在它右边的‘D’就是拐点,统计所有可以到拐点到这个位置的距离就是这个位置的解了。
上面只是初步的想法,实际上如何统计所有可以到拐点也是一个问题。不难想到如果在左边的拐点多于在右边的拐点,那么在左边的拐点一定有一部分是用不到的。更具体的讲,设左拐点数目为n,位置分别为a1,a2…an,右拐点数目为m,位置分别为b1,b2…bm,且当前点位置为k,有  a1<a2<<an<k<b1<b2<<bn ,若a>b,则只有an-m,an-m+1…an和b1,b2…bm是有用的。反之亦然。(其实就是拐点多的那一边离得远的点是没用的,数学表述真的是要死)
接下来就是用前缀和来计算拐点到每个点的距离了,具体的实现要麻烦很多,我想算法20多分钟,写出来快花了一个多小时,虽然是磨了很多洋工。不过写得慢确实是我的一大弊病啊,现在打比赛我都想撞墙了,难道我已经是嘴巴选手了吗……

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

int n;
string s;

long long rights[1000010], lefts[1000010], mins[1000010];
long long suml[1000010],sumr[1000010];

int min(int a, int b)
{
    return a < b ? a : b;
}

int main()
{
    scanf("%d", &n);
    cin >> s;
    lefts[0] = 0;
    rights[n - 1] = 0;
    for (int i = 1; i if (s[i - 1] == 'U') lefts[i]++;
        lefts[i] += lefts[i - 1];
    }
    for (int i = n - 2; i >= 0; i--)
    {
        if (s[i + 1] == 'D') rights[i]++;
        rights[i] += rights[i + 1];
    }
    for (int i = 0; i < n; i++) mins[i] = min(lefts[i]+(s[i]=='U'?1:0), rights[i] + (s[i] == 'D' ? 1 : 0));
    long long t = 0;
    queue<long long> q;

    for (int i = 0; i < n; i++)
    {
        t += q.size();
        if (q.size()  <= mins[i])
        {
            suml[i] = t;
        }
        else
        {
            while (q.size()  > mins[i])
            {
                t -= i - q.front();
                q.pop();
            }
            suml[i] = t;
        }
        if (s[i] == 'U') q.push(i);
    }

    while (!q.empty()) q.pop();
    t = 0;

    for (int i = n - 1; i >= 0; i--)
    {
        t += q.size();
        if (q.size()  <= mins[i])
        {
            sumr[i] = t;
        }
        else
        {
            while (q.size()  > mins[i])
            {
                t -= q.front() - i;
                q.pop();
            }
            sumr[i] = t;
        }
        if (s[i] == 'D') q.push(i);
    }

    for (long long i = 0; i < n; i++)
    {
        if (rights[i] > lefts[i])
        {
            cout << sumr[i] * 2 + suml[i]*2 +i+1 << ' ';
        }
        else if (rights[i] < lefts[i])
        {
            cout << sumr[i]*2 + suml[i] * 2 + n - i << ' ';
        }
        else
        {
            if(s[i]=='D')
                cout << sumr[i] * 2 + suml[i] * 2 + i + 1 << ' ';
            else 
                cout << sumr[i] * 2 + suml[i] * 2 + n - i << ' ';
        }
    }
    cout << endl;
    return 0;
}

378反思

378打的很糟糕。
排名跳水到2000多,TM最后只对了一道题D,A,B,C全WA了,最后发现全是没有考虑到细节,写的时候根本没对拍(也没时间对了)。
A算法最后输出的时候有点细节没考虑到,WA了。
B代码在复制粘贴的时候有个小地方没改过来,当仁不让的WA了,这个诡异的点PROTEST都没测出来我也是醉了,我打378是睡过去了吗。
C没有考虑到下面给出的数列的不一定完全对的上上面的数列,只想了一种难一点情况的-1,还有两三种容易考虑到的-1根本没想,后面practice还WA了两三次。
E现在来看是可以写出来的,没时间了,没时间真的是个大问题啊!
F还没想出来,之后还要看看。

总的来说,之所以打得这么不合水平,就是因为写代码太慢了!!!!
写代码太慢怎么办?多练!!!
12月就校队选拔了,我TM这鬼样怎么去参赛啊……

你可能感兴趣的:(codeforces,acm)