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>
#include <set>
#include <stdio.h>
#include <time.h>
using namespace std;
#define LL __int64
#define pi acos(-1.0)
//#pragma comment(linker, "/STACK:1024000000")
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const double eqs=1e-9;
const int MAXN=400000+10;
int ok[5001][5001];
int k, cnt;
char s[6000], str[6000];
struct node
{
        int flag, sum;
        node *next[2];
};
node *newnode()
{
        int i;
        node *p=new node;
        for(i=0;i<2;i++){
                p->next[i]=NULL;
        }
        p->flag=0;
        p->sum=0;
        return p;
}
void Insert(int st, int len, node *root)
{
        int i, x;
        node *p=root;
        for(i=st;i<len;i++){
                x=s[i]-‘a‘;
                if(p->next[x]==NULL)
                        p->next[x]=newnode();
                p=p->next[x];
                if(ok[st][i]) {
                        p->flag++;
                        p->sum++;
                }
        }
}
void dfs(node *u)
{
        for(int i=0;i<2;i++){
                if(u->next[i]!=NULL){
                        dfs(u->next[i]);
                        u->sum+=u->next[i]->sum;
                }
        }
}
void seach(node *root)
{
        node *p=root;
        while(1){
                k-=p->flag;
                if(k<=0){
                        return ;
                }
                if(p->next[0]!=NULL){
                        if(p->next[0]->sum>=k){
                                str[cnt]=‘a‘;
                                p=p->next[0];
                                cnt++;
                                continue ;
                        }
                        else k-=p->next[0]->sum;
                }
                str[cnt]=‘b‘;
                p=p->next[1];
                cnt++;
        }
}
int main()
{
        int i, j, len, h;
        while(scanf("%s",s)!=EOF){
                scanf("%d",&k);
                len=strlen(s);
                memset(ok,0,sizeof(ok));
                for(i=0;i<len;i++){
                        ok[i][i]=1;
                        if(i<len-1&&s[i]==s[i+1]) ok[i][i+1]=1;
                        if(i<len-2&&s[i]==s[i+2]) ok[i][i+2]=1;
                        if(i<len-3&&s[i]==s[i+3]) ok[i][i+3]=1;
                }
                for(i=5;i<=len;i++){
                        for(j=0;j<len-i+1;j++){
                                h=j+i-1;
                                if(s[j]==s[h]&&ok[j+2][h-2]) ok[j][h]=1;
                        }
                }
                node *root;
                root=newnode();
                for(i=0;i<len;i++){
                        Insert(i, len, root);
                }
                dfs(root);
                cnt=0;
                seach(root);
                for(i=0;i<cnt;i++){
                        printf("%c",str[i]);
                }
                puts("");
        }
        return 0;
}

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

时间: 2024-10-23 16:14:27

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

Codeforces Round #261 (Div. 2) D. Pashmak and Parmida&#39;s problem (树状数组求逆序数 变形)

题目链接 题意: 给出一些数a[n],求(i, j), i<j 的数量,使得:f(1, i, a[i]) > f(j, n, a[j]) . f(lhs, rhs, x) 指在 { [lhs, rhs]范围中,a[k]的值=x } 的数量. 1.  f(1, i, a[i]) 就是指a[i]前面包括a[i]的数中,有几个值=a[i]. 2.  f(j, n, a[j]) 就是指a[j]后面包括a[j]的数中有几个值=a[j]. 虽然a[x]范围不小,但是n的范围是1000,不是很大,所以我们可

Codeforces Round #261 (Div. 2) D. Pashmak and Parmida&#39;s problem (树状数组)

D. Pashmak and Parmida's problem time limit per test 3 seconds memory limit per test 256 megabytes input standard input output standard output Parmida is a clever girl and she wants to participate in Olympiads this year. Of course she wants her partn

Codeforces Round #267 (Div. 2) C. George and Job(DP)补题

Codeforces Round #267 (Div. 2) C. George and Job题目链接请点击~ The new ITone 6 has been released recently and George got really keen to buy it. Unfortunately, he didn't have enough money, so George was going to work as a programmer. Now he faced the follow

Codeforces Round #423 (Div. 2) C 思维,并查集 或 线段树 D 树构造,水

Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) C. String Reconstruction   思维,并查集 或 线段树 题意:一个字符串被删除了,但给出 n条信息,要还原出可能的字典序最小的字符串.信息有:字符串ti,ki个位置xi,表明原本的字符串在xi位置是以字符串ti开头的. tags:惨遭 fst,一开始把所有字符串都存下来,排序做的,结果爆内存了.. 方法1: 考虑并查集,对于字符串 ti,在位置xi,

Codeforces Round #433 (Div. 1) D. Michael and Charging Stations(dp)

题目链接:Codeforces Round #433 (Div. 1) D. Michael and Charging Stations 题意: 一个人每天要加油,1种为1000,1种为2000,如果付全额,会得到10%的回扣放在卡上. 如果卡上有剩余的回扣,可以拿来抵现金.问n天最少需要花多少钱. 题解: 很直观的一个dp就是考虑dp[i][j],表示第i天卡上剩余回扣为j的最小花费. 将所有的数除以100后,j其实是小于40的,严格的说是小于30,官方题解有个证明. 因为卡上不可能积累很多的

Codeforces Round #419 (Div. 2) E. Karen and Supermarket(树形DP)

题目链接:Codeforces Round #419 (Div. 2) E. Karen and Supermarket 题意: 有n件物品,每个物品有一个价格,和一个使用优惠券的价格,不过这个优惠券有一个限制,必须要在第x个使用后才可以使用.现在有m的钱,问最多能买多少个物品. 题解: 每个优惠券都只与一个券有关,所以根据这个关系就可以构成一棵树. 考虑树形dp,dp[i][j][k(0|1)]表示第i个节点所构成的子树中买了j个物品,使用优惠券和不使用优惠券的最少钱. 转移方程看代码详细解释

Codeforces Round #311 (Div. 2) A,B,C,D,E

A. Ilya and Diplomas 思路:水题了, 随随便便枚举一下,分情况讨论一下就OK了. code: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> #include <iostream> #include <cstring> #include <cmath> #define inf 1000000

Codeforces Round #311 (Div. 2)

D 分4种情况讨论 1 不需要加边 , 就是说原本就有一个奇数环,我们只要跑一次二分图就好了 2 加一条边 , 也就是说存在大于等于3个点的联通块 我们对于这个联通块也跑一遍二分图, 可以知道图中所有的 同颜色染色中的点任意相连,都是一个奇数环,那么对于每个联通分量都有相应的数可以计算 3 加两条边,也就是说没有大于两个点的联通块存在,并且有两个点的联通块存在,答案也是可以计算出来的 e*(n-2) 4 加三条边 那么就可以知道每个联通块只有一个点,答案是 n*(n-1)*(n-2)/6; #i

Codeforces Round #311 (Div. 2)--D(图

题意:给出一个图,问最少加多少条边能连出一个奇圈,还要求输出连边的方法种数. 思路:比赛的时候看了一下是图相关的就没多想,也没时间了,其实挺简单的,如果已经有奇圈,那么直接输出0 1,如果最多有两个点相连,那么就是(n-2)×m,就是每条边和另外的任意点连两条边,要么就是没有边,这个就是直接输出结果.. 稍微麻烦一点的是最后一种,联通块有多个点且没有奇圈,这时候需要把联通快黑白染色,同色的点相连就是一个奇圈,dfs的时候统计每个联通块中两种=颜色的个数即可. #include<bits/stdc