题意: 给定两个字符串A,B求长度相同的AB子串,使得子串的前面部分相等,且第一个不相等的位置B>A。求这样的子串个数
场上把两个DP写反了,应该先求前面部分相等的种数,再对于后半部分的大于DP
思路:f[i][j]表示A的前i个字符与B的前j个字符能组成多少相等的子串。
若AB不相等,f[i][j]=f[i--1][j]+f[i][j-1]-f[i-1][j-1];
若AB相等,f[i][j]额外加上f[i-1][j-1],表示一定带有当前这两个字符的相等子串
求完f之后再利用f求解
dp[i][j]表示A前i个字符与B前j个字符的解数。
dp[i][j]=dp[i-1][j]+dp[i][j-1] (原来一直觉得这里要减掉一个dp[i-1][j-1]后来问了别人才知道因为这里如果前面i-1,j-1的子串是符合条件的,那么这里i与j无论放什么都没有关系,所以还要加回去,就正好抵消了)
如果b[j]>a[i] dp[i][j]额外加上f[i-1][j-1]
下附代码:
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 char a[5005],b[5005]; 5 int dp[5005][5005],f[5005][5005]; 6 ll res=0; 7 const int mod=1e9+7; 8 int main(){ 9 scanf("%s%s",a+1,b+1); 10 int n=strlen(a+1),m=strlen(b+1); 11 memset(f,0,sizeof(f)); 12 f[0][0]=1; 13 for (int i=1; i<=m; i++) f[0][i]=1; 14 for (int i=1; i<=n; i++) f[i][0]=1; 15 for (int i=1; i<=n; i++){ 16 for (int j=1; j<=m; j++){ 17 f[i][j]=((f[i-1][j]+f[i][j-1])%mod-f[i-1][j-1]+mod)%mod; 18 if (a[i]==b[j]){ 19 f[i][j]=(f[i-1][j-1]+f[i][j])%mod; 20 } 21 } 22 } 23 for (int i=1; i<=n; i++){ 24 for (int j=1; j<=m; j++){ 25 dp[i][j]=(dp[i-1][j]+dp[i][j-1])%mod; 26 if (a[i]<b[j]) dp[i][j]=(dp[i][j]+f[i-1][j-1])%mod; 27 } 28 } 29 printf("%lld",dp[n][m]); 30 }View Code