•参考资料
[1]:HopeForBetter
•题意
•题解(by 紫书)
•我的理解
用了一上午的时间,参考紫书+上述博文,终于解决了疑惑;
定义第一个颜色序列用串 s 表示,第二个用串 t 表示,下标均从 1 开始;
定义dp(i,j)表示串 s 的前 i 个字符与串 t 的前 j 个字符合并的最小值;
' ? ' 是加什么呢?
分析一下,当前的新序列包含哪些类型的字符:
1)当前新序列包含字符 ch 的开始和结束;
2)当前新序列只包含字符 ch 的开始,而不包含其结束;
3)当前新序列不包含字符 ch;
就情况①,将 si 插入到尾部后,你会发现,这个新插入的元素只会影响 1) 类型字符,怎么影响呢?
当前字符 si 的插入会使得 1) 类型的字符首尾距离增加 1;
那么,情况①中的 ' ? ' 指的就是 s 串的前 i-1 个字符与 t 串中的前 j 个字符的 1) 类型的字符个数;
情况②同理;
那么,如何求解 "s 串的前 i-1 个字符与 t 串中的前 j 个字符的 1) 类型的字符个数" 呢?
定义 w(i,j) 表示串 s 的前 i 个字符与串 t 的前 j 个字符包含的 1) 类型的字符总个数;
![]()
求解w(i,j)1 struct Data 2 { 3 int fir,las; 4 Data(int fir=INF,int las=0):fir(fir),las(las){} 5 }; 6 int w[maxn][maxn]; 7 8 void Preset() 9 { 10 /** 11 a[i].fir:字符 'A'+i 在串s中第一次出现的位置 12 a[i].las:字符 'A'+i 在串s中最后一次出现的位置 13 b[i].fir:字符 'A'+i 在串t中第一次出现的位置 14 b[i].las:字符 'A'+i 在串t中最后一次出现的位置 15 */ 16 Data a[30],b[30]; 17 for(int i=1;i <= n;++i) 18 { 19 Data &tmp=a[s[i]-'A']; 20 tmp.fir=min(tmp.fir,i); 21 tmp.las=i; 22 } 23 for(int i=1;i <= m;++i) 24 { 25 Data &tmp=b[t[i]-'A']; 26 tmp.fir=min(tmp.fir,i); 27 tmp.las=i; 28 } 29 w[0][0]=0; 30 for(int i=0;i <= n;++i) 31 { 32 for(int j=0;j <= m;++j) 33 { 34 if(i) 35 { 36 w[i][j]=w[i-1][j]; 37 int k=s[i]-'A'; 38 if(a[k].fir == i && b[k].fir > j)///判断si是否为首次出现的 39 w[i][j]++; 40 if(a[k].las == i && b[k].las <= j)///判断si是否为结尾字符 41 w[i][j]--; 42 } 43 if(j) 44 { 45 w[i][j]=w[i][j-1]; 46 int k=t[j]-'A'; 47 if(b[k].fir == j && a[k].fir > i)///判断tj是否为首次出现的 48 w[i][j]++; 49 if(b[k].las == j && a[k].las <= i)///判断tj是否为结尾字符 50 w[i][j]--; 51 } 52 } 53 } 54 }求解完 w(i,j) 后,状态转移方程也就完成了:
•Code
![]()
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define INF 0x3f3f3f3f 4 #define INFll 0x3f3f3f3f3f3f3f3f 5 #define ll long long 6 const int maxn=5e3+50; 7 8 int n,m; 9 char s[maxn]; 10 char t[maxn]; 11 struct Data 12 { 13 int fir,las; 14 Data(int fir=INF,int las=0):fir(fir),las(las){} 15 }; 16 int w[maxn][maxn]; 17 ll dp[maxn][maxn]; 18 19 void Preset() 20 { 21 /** 22 a[i].fir:字符 'A'+i 在串s中第一次出现的位置 23 a[i].las:字符 'A'+i 在串s中最后一次出现的位置 24 b[i].fir:字符 'A'+i 在串t中第一次出现的位置 25 b[i].las:字符 'A'+i 在串t中最后一次出现的位置 26 */ 27 Data a[30],b[30]; 28 for(int i=1;i <= n;++i) 29 { 30 Data &tmp=a[s[i]-'A']; 31 tmp.fir=min(tmp.fir,i); 32 tmp.las=i; 33 } 34 for(int i=1;i <= m;++i) 35 { 36 Data &tmp=b[t[i]-'A']; 37 tmp.fir=min(tmp.fir,i); 38 tmp.las=i; 39 } 40 w[0][0]=0; 41 for(int i=0;i <= n;++i) 42 { 43 for(int j=0;j <= m;++j) 44 { 45 if(i) 46 { 47 w[i][j]=w[i-1][j]; 48 int k=s[i]-'A'; 49 if(a[k].fir == i && b[k].fir > j)///判断si是否为首次出现的 50 w[i][j]++; 51 if(a[k].las == i && b[k].las <= j)///判断si是否为结尾字符 52 w[i][j]--; 53 } 54 if(j) 55 { 56 w[i][j]=w[i][j-1]; 57 int k=t[j]-'A'; 58 if(b[k].fir == j && a[k].fir > i)///判断tj是否为首次出现的 59 w[i][j]++; 60 if(b[k].las == j && a[k].las <= i)///判断tj是否为结尾字符 61 w[i][j]--; 62 } 63 } 64 } 65 } 66 ll Solve() 67 { 68 Preset(); 69 dp[0][0]=0; 70 for(int i=0;i <= n;++i) 71 { 72 for(int j=0;j <= m;++j) 73 { 74 if(!(i+j)) 75 continue; 76 dp[i][j]=INFll; 77 78 if(i) 79 dp[i][j]=min(dp[i][j],dp[i-1][j]+w[i-1][j]); 80 if(j) 81 dp[i][j]=min(dp[i][j],dp[i][j-1]+w[i][j-1]); 82 } 83 } 84 return dp[n][m]; 85 } 86 int main() 87 { 88 int test; 89 scanf("%d",&test); 90 while(test--) 91 { 92 scanf("%s%s",s+1,t+1); 93 n=strlen(s+1); 94 m=strlen(t+1); 95 96 printf("%lld\n",Solve()); 97 } 98 return 0; 99 }