由于这个题目的数据量较大,所以枚举比较的动归求解方法就不大行了,,,
此时我们就从当前字符串出发,
主动变换成符合题意的未知串,
然后在所有字典序小于当前串的字符串中寻找未知串是否出现过。
这样就复杂度就从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; }