jzoj4387 [GDOI2016模拟3.15]基因合成 回文树+dp

4 篇文章 0 订阅

Description


这里写图片描述

Solution


60分看完就会了,用头dp
打完然后开始猜结论。最小步数肯定是先变成偶数回文串再往两边加,然后想到了一个manacher乱搞做法,就不会了

对付回文子串可以考虑用回文树。我们知道回文树上每个节点都代表一个字符串,且他的fail指向他的一个最长后缀回文字串,那么我们可以在树上dp。用f[i]表示节点i所代表的串要多少步拼接,转移讨论:
1. 两边加一个。这个可以变成转移之前的节点添加一个字符
2. 由一个长度小于一半的串添加翻转

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))

const int INF=0x3f3f3f3f;
const int N=200005;

char str[N];

int f[N];

struct PalindromeAutomaton {
    int fail[N],rec[N][26],len[N],tot,last;
    void clear() {
        fill(rec,0); fill(len,0); fill(fail,0); fill(f,31);
        tot=last=2; fail[1]=fail[2]=1; len[1]=-1; len[2]=0; f[2]=1; f[1]=2;
    }
    void ins(int ch,int n) {
        int p=last;
        while (str[n]!=str[n-1-len[p]]) p=fail[p];
        if (!rec[p][ch]) {
            rec[p][ch]=++tot; len[tot]=len[p]+2;
            last=rec[p][ch];
            if (len[last]==1) {
                fail[last]=2; f[last]=1;
                return ;
            }
            int k=fail[p];
            while (str[n]!=str[n-len[k]-1]) k=fail[k];
            fail[tot]=rec[k][ch];
            if (len[last]&1) f[last]=len[last];
            else {
                k=fail[last];
                while (len[k]>len[last]/2) k=fail[k];
                f[last]=std:: min(f[p]+1,f[k]+(len[last]/2-len[k])+1);
            }
        } else last=rec[p][ch];
    }
} pam;

int main(void) {
    int T; scanf("%d",&T);
    for (;T--;) {
        pam.clear();
        scanf("%s",str+1);
        int len=strlen(str+1),ans=INF;
        rep(i,1,len) {
            pam.ins(str[i]-'A',i);
        }
        rep(i,3,pam.tot) ans=std:: min(ans,f[i]+len-pam.len[i]);
        printf("%d\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值