codevs2019 Uva10029 递变阶梯
题目描述
递变是指通过增加、减少或改变单词x中的一个字母,使它变成字典中的另一个单词y。比如将dig变成dog,将dog变成do都是递变。递变阶梯是一个按字典序排列的单词序列w1,w2,...wn,满足对于从1到n-1的所有i,单词wi到wi+1都是一次递变。相同的单词之间不能递变。n=15000
给出一部字典,你要计算其中最长的递变阶梯。
题目分析
容易看出这是一个DAG的最长路(类似LIS),那么我们可以想到一个O(n^2)的算法,显然超时.
换个方式想,如果我们枚举每个字符串可以变成的另一个字符串,再判断是否在里面,那么容易发现不会超时(15000*16*26),那么我们可以这样建图,然后走DAG最长路,很可惜我下面这份代码由于Hash的特殊性,无法通过Uva,仅能通过Codevs
题目代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 string str[32000]; 4 const int base = 131; 5 typedef unsigned long long ull; 6 ull f[32000][22]; 7 ull base_pow[22],ans[32000]; 8 ull num[20000000],pla[20000000]; 9 ull mod = 14233333; 10 11 int main(){ 12 int n=0; 13 while(cin>>str[++n])if(str[n]==str[n-1])n--; 14 n--; 15 base_pow[0]=1; 16 for(int i=1;i<=16;i++)base_pow[i]=base_pow[i-1]*base; 17 for(int i=1;i<=n;i++){ 18 f[i][0]=str[i][0]-'a'+1; 19 for(int j=1;j<str[i].length();j++) 20 f[i][j]=f[i][j-1]*base+str[i][j]-'a'+1; 21 num[f[i][str[i].length()-1]%mod]=1; 22 pla[f[i][str[i].length()-1]%mod]=i; 23 } 24 for(int i=1;i<=n;i++)ans[i]=1; 25 for(int i=1;i<=n;i++){ 26 string s=str[i]; 27 for(int j=0;j<s.length();j++){ 28 ull sd = f[i][s.length()-1]; 29 sd-=f[i][j]*base_pow[s.length()-j-1]; 30 if(j-1>=0) 31 sd+=f[i][j-1]*base_pow[s.length()-j-1]; 32 if(num[sd%mod]&&pla[sd%mod]<i&&s.length()-1>0) 33 ans[i]=max(ans[i],ans[pla[sd%mod]]+1); 34 } 35 for(int j=0;j<s.length();j++){ 36 ull sd = f[i][s.length()-1]; 37 sd-=f[i][j]*base_pow[s.length()-j-1]; 38 if(j-1>=0) 39 sd+=f[i][j-1]*base_pow[s.length()-j-1]; 40 if(num[sd%mod]&&pla[sd%mod]>i&&s.length()-1>0) 41 ans[pla[sd%mod]]=max(ans[pla[sd%mod]],ans[i]+1); 42 } 43 for(int j=0;j<str[i].length();j++){ 44 ull sd; 45 for(int k=1;k<=26;k++){ 46 sd = f[i][s.length()-1]; 47 sd-=f[i][j]*base_pow[s.length()-j-1]; 48 sd+=k*base_pow[s.length()-j-1]; 49 if(j-1>=0) 50 sd+=f[i][j-1]*base_pow[s.length()-j]; 51 if(num[sd%mod]&&pla[sd%mod]>i) 52 ans[pla[sd%mod]]=max(ans[pla[sd%mod]],ans[i]+1); 53 } 54 } 55 } 56 ull maxx=0; 57 for(int i=1;i<=n;i++){ 58 maxx=max(maxx,ans[i]); 59 } 60 cout<<maxx; 61 }