bzoj 3325: [Scoi2013]密码

Description

Fish是一条生活在海里的鱼。有一天他很无聊,就到处去寻宝。他找到了位于海底深处的宫殿,但是一扇带有密码锁的大门却阻止了他的前进。通过翻阅古籍,Fish 得知了这个密码的相关信息:

  1. 该密码的长度为N。

  2. 密码仅含小写字母。

  3. 以每一个字符为中心的最长回文串长度。

  4. 以每两个相邻字符的间隙为中心的最长回文串长度。

很快Fish 发现可能有无数种满足条件的密码。经过分析,他觉得这些密码中字典序最小的一个最有可能是答案,你能帮他找到这个密码么?
注意:对于两个串A和B,如果它们的前i个字符都相同,而A的第i+1个字符比B的第i+1个字符小,那么认为是则称密码A 的字典序小于密码B 的字典序,例如字符串abc 字典序小于字符串acb。如果密码A的字典序比其他所有满足条件的密码的字典序都小,则密码A是这些密码中字典序最小的一个。

Input

输入由三行组成。
第一行仅含一个整数N,表示密码的长度。
第二行包含N 个整数,表示以每个字符为中心的最长回文串长度。
第三行包含N - 1 个整数,表示每两个相邻字符的间隙为中心的最长回文串长度。

对于20% 的数据,1 <= n <= 100。
另有30% 的数据,1 <= n <= 1000。
最后50% 的数据,1 <= n <= 10^5。

Output

输出仅一行。输出满足条件的最小字典序密码。古籍中的信息是一定正确的,故一定存在满足条件的密码。

Sample Input

Sample #1

3

1 1 1

0 0

Sample #2

3

1 3 1

0 0

Sample #3

3

1 3 1

2 2

Sample Output

Sample #1

abc

Sample #2

aba

Sample #3

aaa

分析

我们可以根据题意反向构造manacher数组,然后贪心的去填。

代码

#include <bits/stdc++.h>

const int N = 100005;

int n;

int len[N * 2],ans[N];
bool t[N*2][26];

int getMex(int x)
{
    for (int i = 0;; i++)
        if (!t[x][i])
            return i;
}

void build()
{
    int mx = 0, pos = 0;
    for (int i = 1; i <= n * 2 + 1; i++)
    {
        if (i > mx && !(i & 1)) 
            ans[i / 2] = getMex(i);
        if (i + len[i] - 1 > mx)
        {
            for (int j = std::max(mx + 1, i + 1); j <= i + len[i] - 1; j++)
                if (!(j & 1)) 
                    ans[j / 2] = ans[(i * 2 - j) / 2];
            mx = i + len[i] - 1;
            pos = i;
        }
        if (i + len[i] - 1 == mx && i * 2 - mx - 1 > 0) 
            t[mx + 1][ans[(i * 2 - mx - 1) / 2]] = 1;
    }
}

int main()
{
    scanf("%d",&n);
    for (int i = 1; i <= n; i++)
    {
        int x;
        scanf("%d",&x);
        len[i*2] = x + 1;
    }
    for (int i = 1; i < n; i++)
    {
        int x;
        scanf("%d",&x);
        len[i * 2 + 1] = x + 1;
    }
    len[1] = len[n * 2 + 1] = 1;
    build();
    for (int i = 1; i <= n; i++) 
        putchar(ans[i] + 'a');
}
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页