做题感悟:这题和最长公共子序列差不多,开始没注意到数据范围,交上果断wa!!
解题思路: DP+大数 ,用 dp [ i ] [ j ] 代表子串 j 在子串中出现的次数。
动态方程:
s1[ i ] == s2[ j ] --> dp [ i ] [ j ] = dp [ i-1 ] [ j - 1 ] + dp [ i ] [ j -1 ] ; 即:字串 j -1 在 i 中出现的次数(应为s1[ i ] == s2[ j ] 所以相当于串 j ) + 串 j 在 串 i -1 中出现的次数。
s1[ i ] != s2[ j ]--> dp[ i ][ j ] = dp [ i ] [ j - 1 ] ; 即: 串 j 在 串 i -1 中出现的次数(因为s1[ i ] != s2[ j ])
代码:
#include<stdio.h> #include<iomanip> #include<vector> #include<queue> #include<fstream> #include<string.h> #include<stdlib.h> #include<string.h> #include<algorithm> #include<iostream> #define INT long long int using namespace std ; const int MX = 10000 + 10 ; int a[MX][110],b[MX][110] ; char s1[MX],s2[MX] ; void search(int j,int(*a)[110],int(*b)[110]) { int c=0 ; for(int i=0 ;i<100 ;i++) if(a[j][i]+b[j][i]+c>9) b[j+1][i]=a[j][i]+b[j][i]+c-10 , c=1 ; else b[j+1][i]=a[j][i]+b[j][i]+c , c=0 ; } void work(int j,int (*a)[110]) { for(int i=0 ;i<100 ;i++) a[j+1][i]=a[j][i] ; } void print(int x,int (*p)[110]) { int i,j ; for(i=100 ;i>=0 ;i--) if(p[x][i]) break ; if(i==-1) cout<<"0" ; for(j=i ;j>=0 ;j--) cout<<p[x][j] ; cout<<endl ; } int main() { int Tx ; scanf("%d",&Tx) ; while(Tx--) { scanf("%s%s",s1+1,s2+1) ; memset(a,0,sizeof(a)) ; memset(b,0,sizeof(b)) ; int len1=strlen(s1+1) ; int len2=strlen(s2+1) ; for(int i=0 ;i<=10000 ;i++) a[i][0]=1 ; for(int i=1 ;i<=len2 ;i++) { for(int j=1 ;j<=len1 ;j++) if(s2[i]==s1[j]) i%2 ? search(j-1,a,b) : search(j-1,b,a) ; else i%2 ? work(j-1,b) : work(j-1,a) ; i%2 ? memset(a,0,sizeof(a)) : memset(b,0,sizeof(b)) ; } len2%2 ? print(len1,b) : print(len1,a) ; } return 0 ; }