这道题我硬是做了两天多。dp比较好写,但是预处理很难写。自己第一次没写出来,看lrj的,结果反而越看越发愣。但还是受了点启发,改用c[i][j]来表示第一个字符串拿出前i个,第二个字符串拿出前j个时有多少种字母是已经开始了,但还没有结束。
然后又因为memset而超时了,学到的教训就是如果大部分数据范围比较小,还是不要用memset初始化。先读入数据范围,再手写for循环初始化。从超时的3s到AC的0s,这差距还是挺大的!然后时间得到了rank 5!
lrj貌似是用滚动数组做的,他的c数组的计算还是和dp一起进行的,很难看懂。。。。(我已经弃疗了)
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 const int inf=0x3f3f3f3f; 6 const int maxn=5005; 7 char a[maxn],b[maxn]; 8 int len1,len2; 9 int first[255][3],last[255][3]; 10 int dp[maxn][maxn]; 11 int c[maxn][maxn]; 12 int main() 13 { 14 int T; 15 scanf("%d",&T); 16 for(int kase=1;kase<=T;++kase) 17 { 18 scanf("%s%s",a+1,b+1); 19 len1=strlen(a+1),len2=strlen(b+1); 20 for(int i='A';i<='Z';i++) 21 { 22 first[i][1]=first[i][2]=inf; 23 last[i][1]=last[i][2]=-1; 24 } 25 for(int i=0;i<=len1;i++) 26 for(int j=0;j<=len2;j++) 27 c[i][j]=dp[i][j]=0; 28 for(int i=1;i<=len1;i++) 29 { 30 if(first[a[i]][1]==inf) first[a[i]][1]=i; 31 last[a[i]][1]=i; 32 } 33 for(int i=1;i<=len2;i++) 34 { 35 if(first[b[i]][2]==inf) first[b[i]][2]=i; 36 last[b[i]][2]=i; 37 } 38 for(int i=0;i<=len1;i++) 39 { 40 if(i) 41 { 42 c[i][0]=c[i-1][0]; 43 if(first[a[i]][1]==i) c[i][0]++; 44 if(last[a[i]][1]==i&&last[a[i]][2]==-1) c[i][0]--; 45 } 46 for(int j=1;j<=len2;j++) 47 { 48 c[i][j]=c[i][j-1]; 49 if(first[b[j]][2]==j&&first[b[j]][1]>i) c[i][j]++; 50 if(last[b[j]][2]==j&&last[b[j]][1]<=i) c[i][j]--; 51 } 52 } 53 for(int i=0;i<=len1;i++) 54 for(int j=0;j<=len2;j++) 55 { 56 if(i>0&&j>0) dp[i][j]=min(dp[i-1][j],dp[i][j-1])+c[i][j]; 57 else if(i==0&&j>0) dp[i][j]=dp[i][j-1]+c[i][j]; 58 else if(i>0&&j==0) dp[i][j]=dp[i-1][j]+c[i][j]; 59 } 60 printf("%d ",dp[len1][len2]); 61 } 62 }
自己做题的效率一直比较低,这几天忙着迎新和一些学生工作,时间碎片化了。然而这学期学生工作比较多。。。