codeforces #311 557E E. Ann and Half-Palindrome(trie+dp+dfs)

来源:互联网 发布:中国网络电视直播大全 编辑:程序博客网 时间:2024/05/01 11:18

题目链接:

点击打开链接

题目大意:

给出一个字符串,问这个字符串的是半回文的子串的第k个是什么,半回文就是前一半的奇数位满足回文串的条件

题目分析:

这道题要求输出字典序第k大,那么自然而然想到要通过字典树去输出。

首先利用动态规划预处理出是半回文的子串,dp[i][j]代表从i到j的子串是否是半回文

当子串的长度小于等于4时,只要s[i]==s[j]那么就是半回文

其余情况,s[i]==s[j]&&dp[i+2][j-2] 才是半回文,顶多算个递推把

之后就是将符合条件的子串暴力的插入字典树,然后查找第k个字符串就很水了。。。字典树搞一搞就可以了

dp过程o(n^2),字典树插入o(N^2),输出的复杂度是字典树的规模

这道题感觉是一个水题的拼凑,注意输出时加入'\0',防止字符串抽风多输出,谨记。。。。。。。

输出就是dfs递归输出。。。基本功

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#define MAX 5007using namespace std;char s[MAX];char ans[MAX];int k,n,cnt;int dp[MAX][MAX];bool check ( int i , int j){    int len = (j-i+2)/2;    for ( int t = i ; t < len ; t++ )        if ( t%2 == 0 && s[t] != s[j-t] )            return false;    return true;}struct Node{    int ok;    Node* b[2];    Node()        :ok(0)    {        memset ( b , 0 , sizeof ( b ) );    }}*root;void add ( int i  ){    Node * u = root;    for ( int t = i ; t < n ; t++ )    {        if ( !(u->b[s[t]-'a']) )            u->b[s[t]-'a'] = new Node();        u = u->b[s[t]-'a'];        if ( dp[i][t] ) u->ok++;    }}bool flag = false;void dfs ( Node* u , int d ){     if ( flag ) return;    if ( u->ok )    {        cnt += u->ok;        //printf ( "%d %s\n" , cnt , ans );        if ( cnt >= k )        {            ans[d] = 0;            printf ( "%s\n" , ans );            flag = true;            return;        }    }    for ( int i = 0 ; i < 2 ; i++ )    {       if ( !(u->b[i]) ) continue;       ans[d] = (char)(i+'a');       dfs ( u->b[i] , d+1 );    }}void print ( int i , int j  ){    for ( int i = 0 ; i <= j ; i++ )        printf ( "%c" , s[i] );    puts("");}int main ( ){    while ( ~scanf ( "%s" , s ) )    {        root = new Node();        n = strlen(s);        memset ( dp , 0 , sizeof ( dp ) );        for ( int i = 0 ; i < n ; i++ )            dp[i][i] = 1;        scanf ( "%d" , &k );        /*for ( int i = 0 ; i < n ; i++ )            for ( int j = i; j < n ; j++ )            {                if ( s[i] != s[j] ) continue;                if ( check ( i , j ) )                {                    add ( i , j );                       //print ( i , j );                 }              }*/        for ( int i = 1 ; i < n ; i++ )            for ( int j = 0 ; j < n-i ; j++ )            {                if ( s[j] != s[j+i] ) continue;                if ( i <= 4 ) dp[j][i+j] = 1;                else if ( dp[j+2][i+j-2] )                    dp[j][i+j] = 1;            }        for ( int i = 0 ; i < n ; i++ )            add ( i );        //cout << "YES" << endl;        cnt = 0;        flag = false;        dfs ( root , 0 );    }}


0 0
原创粉丝点击