在生物学中,一些生物的结构是用包含其要素的大写字母序列来表示的。生物学家对于把长的序列分解成较短的序列(即元素)很感兴趣。
如果一个集合 P 中的元素可以通过串联(元素可以重复使用,相当于 Pascal 中的 “+” 运算符)组成一个序列 S ,那么我们认为序列 S 可以分解为 P 中的元素。元素不一定要全部出现(如下例中BBC就没有出现)。举个例子,序列 ABABACABAAB 可以分解为下面集合中的元素:
{A, AB, BA, CA, BBC}
序列 S 的前面 K 个字符称作 S 中长度为 K 的前缀。设计一个程序,输入一个元素集合以及一个大写字母序列 S ,设S'是序列S的最长前缀,使其可以分解为给出的集合P中的元素,求S'的长度K。
PROGRAM NAME: prefix
INPUT FORMAT:
(file prefix.in)
输入数据的开头包括 1..200 个元素(长度为 1..10 )组成的集合,用连续的以空格分开的字符串表示。字母全部是大写,数据可能不止一行。元素集合结束的标志是一个只包含一个 “.” 的行。集合中的元素没有重复。接着是大写字母序列 S ,长度为 1..200,000 ,用一行或者多行的字符串来表示,每行不超过 76 个字符。换行符并不是序列 S 的一部分。
OUTPUT FORMAT:
(file prefix.out)
只有一行,输出一个整数,表示 S 符合条件的前缀的最大长度。
A AB BA CA BBC . ABABACABAABC
11
第一反应是dfs,但复杂度太高,估计会超时
又想到可以对于每一个合法位置,可以通过集合内的字符串往后扩展,如果扩展成功则将更新答案最大值
/* ID: your_id_here PROG: prefix LANG: C++ */ #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int cnt=0,ans=0,i=0,len,j,k; char s[200015]={0},tmp[77]; bool dp[200015]={false}; struct Node { char s[11]; int len; }pri[205]; bool mycmp() { for(k=0;k<pri[j].len;++k) if(s[i+k+1]!=pri[j].s[k]) return false; return true; } int main() { freopen("prefix.in","r",stdin); freopen("prefix.out","w",stdout); while(scanf("%s",pri[cnt].s),pri[cnt].s[0]!='.') { pri[cnt].len=strlen(pri[cnt].s); ++cnt; } while(1==scanf("%s",tmp)) {//s串可以分成多行 strcpy(s+1+len,tmp); len+=strlen(tmp); } dp[0]=true; while(i<=ans&&i<=len) { if(dp[i]) for(j=0;j<cnt;++j) if(!dp[i+pri[j].len]&&mycmp()) { dp[i+pri[j].len]=true; ans=max(ans,i+pri[j].len); } ++i; } printf("%d\n",min(len,ans)); return 0; }