由于这个题目的数据量较大,所以枚举比较的动归求解方法就不大行了,,,
此时我们就从当前字符串出发,
主动变换成符合题意的未知串,
然后在所有字典序小于当前串的字符串中寻找未知串是否出现过。
这样就复杂度就从O(n^2)降到了O(nlog(n));
其实两种方法的动归方程都是一样的,就是比较的方式不同,,
第二种方法优化了字符串比较。。。。
状态:dp[i]表示前i个单词所能形成的递变阶梯最大值。。。
状态转移:dp[i] = dp[x]+1;(s[i]与s[x]满足题目中的变化关系)
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 25005
#define N 20
char str[M][N], s[N];
int ans, n, dp[M];
void Add(int x, int y, int c)
{
memset(s,0,sizeof(s));
for(int i = 0; i < y; i++) s[i] = str[x][i];
s[y] = 'a'+c;
for(int i = y; str[x][i]; i++) s[i+1] = str[x][i];
}
void Change(int x, int y, int c)
{
memset(s,0,sizeof(s));
for(int i = 0; i < y; i++) s[i] = str[x][i];
s[y] = 'a'+c;
for(int i = y+1; str[x][i]; i++) s[i] = str[x][i];
}
void Delete(int x, int y)
{
memset(s,0,sizeof(s));
for(int i = 0; i < y; i++) s[i] = str[x][i];
for(int i = y+1; str[x][i]; i++) s[i-1] = str[x][i];
}
int search(int l, int r)
{
int mid;
while(l<=r)
{
mid = (r+l)/2;
if(!strcmp(str[mid],s)) return mid;
else if(strcmp(str[mid],s)>0) r = mid-1;
else l = mid+1;
}
return 0;
}
int main ()
{
n = 0;
ans = 0;
dp[1] = 1;
while(~scanf("%s",str[++n]));
n-=1;
for(int i = 2; i <= n; i++)
{
dp[i] = 1;
for(int j = 0; str[i][j]; j++)
{
Delete(i,j);
int cur;
if(cur = search(1,i)) dp[i] = max(dp[i],dp[cur]+1);
for(int k = 0; 'a'+k<str[i][j]; k++)
{
Add(i,j,k);
if(cur = search(1,i)) dp[i] = max(dp[i],dp[cur]+1);
Change(i,j,k);
if(cur = search(1,i)) dp[i] = max(dp[i],dp[cur]+1);
}
}
ans = max(ans,dp[i]);
}
printf("%d\n",ans);
return 0;
}