G - Virus synthesis(回文树+dp)
Posted zhangbuang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了G - Virus synthesis(回文树+dp)相关的知识,希望对你有一定的参考价值。
题意
有AGTC四种字符,一开始有一个空串,每次操作,可以在首或尾加任意个字符,或者将已有字符镜面复制(左右两种复制方法),要求最少的操作步数使得得到给出的字符串
Solution:
我们要知道我们要求的是什么,是每一给回文串的所需要的最少的构造操作加上n-这个串的长度
然后就考虑如何求前者
题解:https://blog.csdn.net/nudt_spy/article/details/100061078
Code;
#include<bits/stdc++.h> #define N 100010 #define INF 0x3f3f3f3f #define eps 1e-6 #define pi 3.141592653589793 #define mod 777777777 #define P 1000000007 #define LL long long #define pb push_back #define fi first #define se second #define cl clear #define si size #define lb lower_bound #define ub upper_bound #define bug(x) cerr<<#x<<" : "<<x<<endl #define mem(x,y) memset(x,0,sizeof(int)*(y+3)) #define sc(x) scanf("%d",&x) #define scc(x,y) scanf("%d%d",&x,&y) #define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; typedef pair<int,int> pp; char s[N]; int ans; int tot; struct PAM int next[N][4] ;//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成 int fail[N] ;//fail指针,失配后跳转到fail指针指向的节点 int cnt[N]; //表示节点i表示的回文串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的) int num[N] ; //表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数(包括本身)。 int len[N] ;//len[i]表示节点i表示的回文串的长度 int s[N] ;//存放添加的字符 int half[N]; int dp[N]; int last ;//指向上一个字符所在的节点,方便下一次add int n ;//字符数组指针 int p ;//节点指针 //r为结尾的回文串的长度一定可以分成logn段等差数列 inline int newnode ( int l ) //新建节点 for ( int i = 0 ; i < 4 ; ++ i ) next[p][i] = 0 ; cnt[p]= 0 ; num[p] = 0 ; len[p] = l ; return p ++ ; inline void init () //初始化 p = 0 ; newnode ( 0 ) ; newnode ( -1 ) ; last = 0 ; n = 0 ; s[n] = -1 ;//开头放一个字符集中没有的字符,减少特判 fail[0] = 1 ; half[0]=half[1]=1; inline int get_fail ( int x ) //和KMP一样,失配后找一个尽量最长的 while ( s[n - len[x] - 1] != s[n] ) x = fail[x] ; return x ; inline void add ( int c ) // c -= ‘a‘ ; s[++ n] = c ; int cur = get_fail ( last ) ;//通过上一个回文串找这个回文串的匹配位置 if ( !next[cur][c] ) //如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串 int now = newnode ( len[cur] + 2 ) ;//新建节点 fail[now] = next[get_fail ( fail[cur] )][c] ; next[cur][c] = now ; if (len[now]==1) half[now]=0;else int pos=half[cur]; while ( s[n - len[pos] - 1] != s[n]||len[pos]+2>len[now]/2 ) pos = fail[pos] ; half[now]=next[pos][c]; if (len[now]&1) dp[now]=dp[fail[now]]+len[now]-len[fail[now]]; else if (len[now]<=2) dp[now]=len[now]; else dp[now]=min(dp[cur]+1,dp[half[now]]+len[now]/2-len[half[now]]+1); last = next[cur][c] ; ans=min(ans,dp[last]+tot-len[last]); A; int main(int argc, char const *argv[]) int T; sc(T); while(T--) scanf("%s",s+1); int n=strlen(s+1); tot=n; A.init(); ans=1e9; for(int i=1;i<=n;i++) int x; if (s[i]==‘A‘) x=0;else if (s[i]==‘G‘) x=1;else if (s[i]==‘C‘) x=2;else x=3; A.add(x); printf("%d\n",ans); return 0;
以上是关于G - Virus synthesis(回文树+dp)的主要内容,如果未能解决你的问题,请参考以下文章
[BZOJ4044]Virus synthesis 回文自动机的DP
luogu P4762 [CERC2014]Virus synthesis (回文自动机)
bzoj 4044: [Cerc2014] Virus synthesis回文自动机+dp
bzoj4044/luoguP4762 [Cerc2014]Virus synthesis(回文自动机+dp)