[字典树] Codeforces 557E Ann and Half-Palindrome

题意:

给一个长度为5000的ab串,问你第k大的半回文子串是什么

所谓的半回文串就是下标是奇数的位置前后相等就好了。

思路:

首先发现串的长度只有5000,可以做一个类似区间dp的预处理

处理出dp[i][j]代表第i到j子串是不是半回文子串

然后依次把原串的所有子串插入字典树,并在节点标记个数

然后最后dfs一下k个就好了

代码:

#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
using namespace std;
#define N 20000007
char v[5555],ans[5555];
int dp[5555][5555],k;
struct Trie
{
    int next[N][2],mark[N];
    int root,L;
    int newnode()
    {
        memset(next[L],-1,sizeof(next[L]));
        mark[L++]=0;
        return L-1;
    }
    void go()
    {
        L=0;
        root=newnode();
    }
    void init(int l,int r)
    {
        int p=root;
        for(int i=l; i<=r; i++)
        {
            int tep=v[i]-'a';
            if(next[p][tep]==-1) next[p][tep]=newnode();
            p=next[p][tep];
            if(dp[l][i]) mark[p]++;
        }
    }
    void dfs(int x,int y)
    {
        if(k-mark[x]>0)
        {
            k-=mark[x];
            for(int i=0; i<2; i++)
            {
                ans[y]='a'+i;
                if(next[x][i]!=-1) dfs(next[x][i],y+1);
                if(k<=0) return ;
            }
        }
        else
        {
            k-=mark[x];
            ans[y]='\0';
            return ;
        }
    }
} ac;
int main()
{
    while(scanf("%s",v)!=-1)
    {
        scanf("%d",&k);
        int len=strlen(v);
        for(int i=0;i<len;i++) for(int j=0;j<len;j++) dp[i][j]=0;
        for(int i=0; i<len; i++)
        {
            dp[i][i]=1;
            if(v[i]==v[i+1]) dp[i][i+1]=1;
            if(v[i]==v[i+2]) dp[i][i+2]=1;
            if(v[i]==v[i+3]) dp[i][i+3]=1;
        }
        for(int i=4; i<len; i++) for(int j=0; j+i<len; j++) if(v[j]==v[j+i]&&dp[j+2][j+i-2]) dp[j][j+i]=1;
        ac.go();

        for(int i=0; i<len; i++) ac.init(i,len-1);
        ac.dfs(0,0);
        puts(ans);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-30 03:59:18

[字典树] Codeforces 557E Ann and Half-Palindrome的相关文章

C. Watto and Mechanism 字典树 Codeforces Round #291 (Div. 2)

C. Watto and Mechanism time limit per test 3 seconds memory limit per test 256 megabytes input standard input output standard output Watto, the owner of a spare parts store, has recently got an order for the mechanism that can process strings in a ce

Codeforces Round #311 (Div. 2) E. Ann and Half-Palindrome (DP+字典树)

题目地址:传送门 先用dp求出所有的符合要求的半回文串,标记出来.然后构造字典树.然后再dfs一遍求出所有节点的子树和,最后搜一遍就能找出第k个来了. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map>

Codeforces 577E Ann and Half-Palindrome 字典树

题目链接 题意: 若一个字符串是半回文串,则满足第一位和最后一位相等, 第三位和倒数第三位相等,如此类推. 给定一个字符串s,输出s的所有子串中的半回文串字典序第k大的 字符串. good[i][j] 表示 s(i,j) 是半回文串. 把这些回文串插到字典树里 在字典树上找第k个叶子节点. 插入时:插入以i点开头的所有半回文串. #include <iostream> #include <string> #include <vector> #include <cs

CodeForces 706D Vasiliy&#39;s Multiset (字典树查询+贪心)

题意:最开始的时候有一个集合,集合里面只有一个元素0,现在有q次操作,操作分为3种: + x: 表示向集合中添加一个元素x - x:表示删除集合中值为x的一个元素 ? x:表示查询集合中与x异或的最大值为多少 析:这是一个字典树的应用,不过确实没看出来....主要思想是这样,先用10进制数,转成二进制数,记下每个结点的0,1的个数,这样增加和删除,就是对01的删除, 剩下的就是查询,那么尽量让0和1XOR是最大的,所以,对于给定数,我们要去尽量他的XOR数,如果找到就加上,找不到,就找下一个.这

codeforces 455B A Lot of Games(博弈,字典树)

题目大意:给定n,表示字符串集合.给定k,表示进行了k次游戏,然后是n个字符串.每局开始,字符串为空串,然后两人轮流在末尾追加字符,保证新的字符串为集合中某字符串的前缀,不能操作者输,新一轮由上一句输的人先手. 解题思路:首先对字符集合建立字典树,然后根据博弈的必胜必败性质搜索出先手的决策状态,可决定胜败3,只能胜利2,只能失败1,不可掌控(即对手可决定胜败)0. 对于状态3,为必胜,可以采用前K-1场败,然后保证第K场自己先手,取必胜方案. 对于状态2,无论则们走都是赢的话,肯定是两个人轮流胜

Codeforces 706D Vasiliy&#39;s Multiset(可持久化字典树)

[题目链接] http://codeforces.com/problemset/problem/706/D [题目大意] 要求实现一个集合中的三个操作,1:在集合中加入一个元素x,2:从集合中删除一个元素x(保证x存在),3:要求从集合中选出一个数,使得其与给出的数x的异或值最大,输出这个异或值. [题解] 可以将所有的以二进制形式存在01字典树上,删除即插入权值为-1的二进制串,对于异或值最大的操作,我们只要在字典树上按位贪心,从最高位开始尽量保证该位存在最后就能得到答案.写代码的时候直接写了

(字典树)codeforces - 706D Vasiliy&#39;s Multiset

原题链接:http://codeforces.com/problemset/problem/706/D 题意:需要你模拟一个多重集合(初始拥有0),该集合拥有三个功能 1.+ x  增加一个x(可以同时存在多个x,因为是多重集合) 2.-  x 去掉一个x 3.? x  输出在这个集合中和x异或最大的值. 分析:有20万个操作,很容易想到树形数据结构,我们可以看到每个x最多只有10^9,而1<<30比10^9大一点,所以10^9次方最多就是29位的01串,可以维护一个字典树. 每个节点有两个分

(字典树)codeforces - 713A Sonya and Queries

原题链接:http://codeforces.com/problemset/problem/713/Attr 题意:一个集合,有三个操作,+-?,其中+和-和上一次cf的字典树那题是一个意思,?操作是统计满足01模式串的字典树中数的个数.如果模式串比字典中的数长就补全数,如果数长就补全模式串. 分析: 这题居然写了一个小时,一开始20分钟差不多写完了,但是一直坑在两种长度不同的情况上,后来仔细一想,卧槽,so easy啊,直接默认全部补全到18位不就行了..那样这题就是一个简单的求前缀的个数.

Codeforces 455B A Lot of Games(字典树+博弈)

题目连接: Codeforces 455B A Lot of Games 题目大意:给定n,表示字符串集合.给定k,表示进行了k次游戏,然后是n个字符串.每局开始,字符串为空串,然后两人轮流在末尾追加字符,保证新的字符串为集合中某字符串的前缀,不能操作者输,新一轮由上一句输的人先手. 解题思路:首先对字符集合建立字典树,然后根据博弈的必胜必败性质搜索出先手的决策状态,可决定胜败3,只能胜利2,只能失败1,不可掌控(即对手可决定胜败)0. 对于状态3,为必胜,可以采用前K-1场败,然后保证第K场自