UVA1625
题目大意:
给出两个字符串,其中只有 ‘A' ~ 'Z' 这26个英文字母。定义 L(G)= 字符 'G' 在一个字符串中第一次出现的位置减去最后一次出现的位置。按顺序组合给出的连个字符串(例:"ABC" 和 “DEF" 可以组合为 "ABCDEF" 或 “ADBECF",即在组合出来的字符串中的给出的两个子串自己顺序不能乱),求 SUM_OF_L 的最小值。
解题思路:
先预处理出 have[i][j] = 当把第一个字符串中的前 i 个字母和第二个字符串中的前 j 个字母放在一起以后有多少个字母已经 “开始” 但还没有 “结束” (“结束” 是指后面已经没有这个字母了),那么不难得出状态转移方程 dp[i][j] = min(dp[i-1][j]+have[i-1][j], dp[i][j-1]+have[i][j-1]),其中 dp[i][j] = 当把第一个字符串中的前 i 个字母和第二个字符串中的前 j 个字母放在一起以后 SUM_OF_L 的最小值,相信读者不难发现这部分很像最长公共子序列,对吧?
那么现在的问题就只剩下如何预处理出 have[i][j],其实也不难,记录下各个字符串中的各个字母第一次出现和最后一次出现的位置,然后每一个 have[i][j] 都在 have[i][j-1] 的基础上更新即可。
AC代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 6 using namespace std; 7 const int maxn=5003; 8 char s1[maxn],s2[maxn]; 9 int dic[3][30][2]; 10 int dp[maxn][maxn],have[maxn][maxn]; 11 int main(){ 12 // freopen("IN.txt","r",stdin); 13 int T; 14 scanf("%d",&T); 15 while(T--){ 16 memset(dic,0,sizeof(dic)); 17 scanf("%s",s1+1); int len1=strlen(s1+1); 18 scanf("%s",s2+1); int len2=strlen(s2+1); 19 for(int i=0;i<=len1;i++){ 20 for(int j=0;j<=len2;j++) dp[i][j]=have[i][j]=0; 21 } 22 for(int i=1;i<=len1;i++){ 23 if(dic[1][s1[i]-'A'][0]==0){ 24 dic[1][s1[i]-'A'][0]=i; 25 } 26 dic[1][s1[i]-'A'][1]=i; 27 } 28 for(int i=1;i<=len2;i++){ 29 if(dic[2][s2[i]-'A'][0]==0){ 30 dic[2][s2[i]-'A'][0]=i; 31 } 32 dic[2][s2[i]-'A'][1]=i; 33 } 34 for(int i=1;i<=len1;i++){ 35 have[i][0]=have[i-1][0]; 36 if(dic[1][s1[i]-'A'][0]==i) have[i][0]++; 37 if(dic[1][s1[i]-'A'][1]==i&&dic[2][s1[i]-'A'][0]==0) have[i][0]--; 38 } 39 for(int i=1;i<=len2;i++){ 40 have[0][i]=have[0][i-1]; 41 if(dic[2][s2[i]-'A'][0]==i) have[0][i]++; 42 if(dic[2][s2[i]-'A'][1]==i&&dic[1][s2[i]-'A'][0]==0) have[0][i]--; 43 } 44 for(int i=1;i<=len1;i++){ 45 for(int j=1;j<=len2;j++){ 46 have[i][j]=have[i][j-1]; 47 if(dic[1][s2[j]-'A'][1]<=i && dic[2][s2[j]-'A'][1]<=j) have[i][j]--; 48 if((dic[1][s2[j]-'A'][0]==0||dic[1][s2[j]-'A'][0]>i) 49 &&(dic[2][s2[j]-'A'][0]==0||dic[2][s2[j]-'A'][0]>=j)) have[i][j]++; 50 } 51 } 52 for(int i=1;i<=len1;i++) dp[i][0]=dp[i-1][0]+have[i-1][0]; 53 for(int j=1;j<=len2;j++) dp[0][j]=dp[0][j-1]+have[0][j-1]; 54 for(int i=1;i<=len1;i++){ 55 for(int j=1;j<=len2;j++){ 56 dp[i][j]=min(dp[i-1][j]+have[i-1][j],dp[i][j-1]+have[i][j-1]); 57 } 58 } 59 printf("%d\n",dp[len1][len2]); 60 } 61 62 return 0; 63 }
“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”