题目大意:
两个字符串
每次可以从任意一个字符串的开始选一个加入新的字符串
定义一个字符串的价值为其各字符跨度之和,定义一个字符串内某字符跨度为该字符最后一次出现的下标与第一次出现的下标之差
求新字符串的最小价值
思路:
dp
dp数组表示第一个字符串选走了前i个,第二个选走了前j个的最小价值
每个dp都可以从i-1,j或i,j-1转移过来
在转移过程中,我们只需要记录一下还有多少个字符还没有结束就可以很容易的转移了
记录这个数组还需要记录每个字符在每两个串里第一次和最后一次出现的位置
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<cstdlib> 6 #include<vector> 7 #include<queue> 8 #include<algorithm> 9 #define inf 2147483611 10 #define ll long long 11 #define MAXN 5010 12 #define MOD 905229641 13 using namespace std; 14 int T,x,sa[30],ea[30],sb[30],eb[30],n,m,c[2][MAXN],dp[2][MAXN]; 15 char ca[MAXN],cb[MAXN]; 16 int main() 17 { 18 scanf("%d",&T); 19 while(T--) 20 { 21 memset(sa,0,sizeof(sa)); 22 memset(sb,0,sizeof(sb)); 23 memset(ea,0,sizeof(ea)); 24 memset(eb,0,sizeof(eb)); 25 c[1][0]=dp[1][0]=0; 26 scanf("%s%s",ca+1,cb+1); 27 n=strlen(ca+1),m=strlen(cb+1); 28 for(int i=1;i<=n;i++) 29 { 30 x=ca[i]-'A'; 31 if(!sa[x]) sa[x]=i; 32 ea[x]=i; 33 } 34 for(int i=1;i<=m;i++) 35 { 36 x=cb[i]-'A'; 37 if(!sb[x]) sb[x]=i; 38 eb[x]=i; 39 } 40 int p,q; 41 bool last=1,first=0; 42 for(int i=0;i<26;i++) {if(!sa[i]) sa[i]=inf;if(!sb[i]) sb[i]=inf;} 43 for(int i=0;i<=n+1;i++) 44 { 45 for(int j=0;j<=m+1;j++) 46 { 47 if(!i&&!j) continue; 48 p=ca[i]-'A',q=cb[j]-'A',dp[last][j]=inf; 49 if(i) dp[last][j]=min(dp[first][j]+c[first][j],dp[last][j]); 50 if(j) dp[last][j]=min(dp[last][j-1]+c[last][j-1],dp[last][j]); 51 if(i) 52 { 53 c[last][j]=c[first][j]; 54 if(sa[p]==i&&sb[p]>j) c[last][j]++; 55 if(ea[p]==i&&eb[p]<=j) c[last][j]--; 56 } 57 if(j) 58 { 59 c[last][j]=c[last][j-1]; 60 if(sb[q]==j&&sa[q]>i) c[last][j]++; 61 if(eb[q]==j&&ea[q]<=i) c[last][j]--; 62 } 63 } 64 swap(first,last); 65 } 66 printf("%d ",dp[first][m]); 67 } 68 }