洛谷 3469 & bzoj 1123 [POI2008]BLO-Blockade 题解

博客观赏效果更佳

题意简述

一个字符串S,长度5000(时间空间都够平方做),只有’a’和’b’两个字符组成。一个字符串A是“半回文”的,当且仅当,对于所有的奇数 i < = ( A + 1 ) / 2 i<=(|A|+1)/2 ,满足A的正数第 i i 个和 A A 的倒数第 i i 个相等。

请你求出, S S 的所有半回文的子串中,字典序排序第 k k 位的是哪个。

思路框架

d p dp 求出哪些子串是半回文的,加入到TRIE树中,用类似二叉查找树的方法找到第 k k 个即珂。

具体思路

d p [ l ] [ r ] dp[l][r] 表示 [ l , r ] [l,r] 这一段子串是否是“半回文”的。如果 s [ l ] = = s [ r ] s[l]==s[r] ,才有珂能半回文,否则直接设为 0 0

如果l+2>=r-2,那么只需要满足 s [ l ] = = s [ r ] s[l]==s[r] ,就是半回文了。
否则,还需要使 d p [ l + 2 ] [ r 2 ] dp[l+2][r-2] 为真, d p [ l ] [ r ] dp[l][r] 才为真。

然后TRIE树上记录一个子树和。设指向字符’a’的是左儿子,‘b’是右儿子。由于’a’的字典序小于’b’,所以,如果左儿子的size<=k,那么第 k n u m [ l e f t s o n ] k-num[leftson] 个就在左子树里面。否则,就在右子树里面找第 k n u m [ r i g h t s o n ] k-num[rightson] 即珂。其中 n u m [ u ] num[u] 表示节点 u u 是否表示一个半回文串。

代码:

#include <bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
    #define N 5333
    #define F(i,l,r) for(int i=l;i<=r;++i)
    #define D(i,r,l) for(int i=r;i>=l;--i)
    #define Fs(i,l,r,c) for(int i=l;i<=r;c)
    #define Ds(i,r,l,c) for(int i=r;i>=l;c)
    #define Tra(i,u) for(int i=G.Start(u),__v=G.To(i);~i;i=G.Next(i),__v=G.To(i))
    #define MEM(x,a) memset(x,a,sizeof(x))
    #define FK(x) MEM(x,0)

    char s[N];
    int k;int n;
    void Input()
    {
        scanf("%s%d",s+1,&k); n=strlen(s+1);
    }

    class Trie //TRIE树
    {
    public:
        int num[N*1000];int T[N*1000][2];int cnt; //开个N*1000就够了
        bitset<N> dp[N];int Max[N]; //bitset节省空间,大约是除以一个32的常数,因为其利用率高
        void Init()
        {
            cnt=0;
            D(i,n,1) 
            {
                dp[i][i]=1;Max[i]=i;
                F(j,i+1,n)
                {
                    if (s[i]==s[j]) 
                    {
                        if (i+2>=j-2) dp[i][j]=1;
                        else dp[i][j]=dp[i+2][j-2];
                    }
                    if (dp[i][j]) Max[i]=max(Max[i],j); //Max[i]: 最远的j满足dp[i][j]=1
                }
            }
        }
        void Insert(int l,int r)
        {
            int pos=0;
            F(i,l,r)
            {
                int id=s[i]-'a';
                if (T[pos][id]==0) T[pos][id]=++cnt;
                if (dp[l][i]) num[T[pos][id]]++; //暴力插入,反正平方能做

                pos=T[pos][id];
            }
        }
        string ans;
        void DFS(int u)
        {
            string tmp=ans;
            if (k>0 and T[u][0])
            {
                k-=num[T[u][0]];
                ans+='a';
                DFS(T[u][0]);
            }
            if (k>0 and T[u][1])
            {
                ans=tmp;
                k-=num[T[u][1]];
                ans+='b';
                DFS(T[u][1]);
            }
        }
    }T;
    void Soviet()
    {
        T.Init();
        F(i,1,n) T.Insert(i,T.Max[i]);
        T.DFS(0);
        printf("%s\n",T.ans.c_str());
    }

    #define Flan void
    Flan IsMyWife()
    {
        Input();
        Soviet();
    }
}
int main()
{
    Flandre_Scarlet::IsMyWife();
    getchar();getchar();
    return 0;
}
发布了210 篇原创文章 · 获赞 8 · 访问量 8973

猜你喜欢

转载自blog.csdn.net/LightningUZ/article/details/103650090