• 周四. 6月 30th, 2022

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

牛客多校第五场D Double Strings

admin

11月 28, 2021

题意: 给定两个字符串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

发表评论

您的电子邮箱地址不会被公开。