如何用 Lyndon 无脑构造

QOJ9729 Dividing Sequence

给定序列 a,把它划分成两个子序列 b,c,要求字典序 bc,求字典序最小的 c

字典序问题,可以在 Lyndon 分解上考虑,设分解得到 s=w1++wk

考虑第一个字符分给谁,如果分给 b 的话,那 c 只能以 w1 的一个后缀开头,

而这样显然不优(令 b=,c=a 就可以使 cw1 开头),所以第一个字符分给 c

可以发现 c 至少要取完 w1,而且取的越少越好(因为后面的 Lyndon 串字典序更小),

所以不妨先把 w1 分给 c,可以发现若 w1>w2 直接把后面所有字符分给 b 即可,

w1=w2,可以发现 b 至少要取完 w2,规约到 w3++wk 的子问题,继续这样做即可。

原题 n5000,可能爆标了?

#include <cstdio>
#include <cstring>
int T, n, a[5050], w[5050], p[5050], Z[5050];
int main()
{
    scanf("%d", &T);
    while (T--)
    {
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i)
            scanf("%d", a + i);
        int i = 1, j, k, c = 0, d = 0, o = 0;
        while (i <= n)
        {
            j = i + 1, k = i;
            while (j <= n)
            {
                if (a[j] == a[k])
                    ++j, ++k;
                else if (a[j] > a[k])
                    ++j, k = i;
                else
                    break;
            }
            ++d;
            while (i <= k)
                w[++c] = i, p[c] = d, i += j - k;
        }
        w[c + 1] = n + 1, p[c + 1] = -1;
        for (int i = 1; i <= c; i += 2)
        {
            for (int j = w[i]; j < w[i + 1]; ++j)
                Z[++o] = a[j];
            if (p[i] != p[i + 1])
                break;
        }
        printf("%d\n", o);
        for (int i = 1; i <= o; ++i)
            printf("%d ", Z[i]);
        puts("");
    }
    return 0;
}
posted @   Jijidawang  阅读(43)  评论(5编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示