题目大意
给出两个非空字符串 s s s和 t t t,每次可以将字符串 s s s中的任意一个字符串 t t t删除,求最小次数删除使得字符串 s s s中不会出现字符串 t t t,并求出有多少种不同的方案。
如果删除的序列相同而顺序不同,也看作相同的方案。如 { 3 , 5 } \{3,5\} {3,5}和 { 5 , 3 } \{5,3\} {5,3}是相同的方案。
输出最小删除次数与以最小删除次数删除的方案数对 1 0 9 + 7 10^9+7 109+7取模后的值。
有
q
q
q组数据。
1
≤
q
≤
50
1\leq q\leq 50
1≤q≤50,
1
≤
∑
∣
s
∣
≤
500
1\leq \sum|s|\leq 500
1≤∑∣s∣≤500,
1
≤
∑
∣
t
∣
≤
500
1\leq \sum|t|\leq 500
1≤∑∣t∣≤500
题解
设 s s s的长度为 n n n, t t t的长度为 m m m。
首先要求出 t t t在 s s s中出现的位置。可以用KMP,但没有必要,暴力求的总时间复杂度为 O ( ∑ ( n × m ) ) O(\sum(n\times m)) O(∑(n×m)),而 ∑ ( n × m ) ≤ ( ∑ n ) × ( ∑ m ) ≤ 250000 \sum(n\times m)\leq (\sum n)\times (\sum m)\leq 250000 ∑(n×m)≤(∑n)×(∑m)≤250000,完全是可以的。
令各个位置分别为
a
1
,
a
2
,
…
,
a
k
a_1,a_2,\dots,a_k
a1,a2,…,ak。
k
=
0
k=0
k=0需要特判,输出0,1。
设 f i f_i fi表示让前 i i i个位置都不存在的最小删除次数, g i g_i gi表示其方案数。首先删去的两段不能有交集,令 k k k满足 a k > a i + m − 1 a_k>a_i+m-1 ak>ai+m−1的最小的数,则转移为 f j = min ( f j , f i + 1 ) f_j=\min(f_j,f_i+1) fj=min(fj,fi+1),其中 j > i j>i j>i且 a j ≤ a k + m − 1 a_j\leq a_k+m-1 aj≤ak+m−1
注意 i = 1 i=1 i=1时,对于满足 a j ≤ a i + m − 1 a_j\leq a_i+m-1 aj≤ai+m−1的 j j j, f j = 1 f_j=1 fj=1。
在求 f f f时顺便求 g g g即可,具体见代码。
时间复杂度为 O ( ∑ ( n × m ) + ∑ n 2 ) O(\sum(n\times m)+\sum n^2) O(∑(n×m)+∑n2)。
code
#include<bits/stdc++.h>
using namespace std;
int T,s1,t1,a1,a[505];
long long ans1,ans2,f[505],g[505];
long long mod=1000000007;
char s[505],t[505];
void gt(){
for(int i=1;i<=s1-t1+1;i++){
int j=1;
for(j=1;j<=t1&&s[i+j-1]==t[j];j++);
if(j==t1+1) a[++a1]=i;
}
}
int main()
{
scanf("%d",&T);
while(T--){
scanf("%s%s",s+1,t+1);
s1=strlen(s+1);
t1=strlen(t+1);
a1=0;gt();
if(a1==0){
printf("0 1\n");
continue;
}
for(int i=1;i<=a1;i++){
f[i]=1e9;g[i]=0;
}
for(int j=1;a[j]<=a[1]+t1-1&&j<=a1;j++){
if(f[j]>1){
f[j]=1;
g[j]=1;
}
else if(f[j]==1){
g[j]=(g[j]+g[1])%mod;
}
}
for(int i=1;i<=a1;i++){
int lst=i+1;
while(a[lst]<=a[i]+t1-1&&lst<=a1) ++lst;
if(lst>a1) continue;
for(int j=lst;a[j]<=a[lst]+t1-1&&j<=a1;j++){
if(f[j]>f[i]+1){
f[j]=f[i]+1;
g[j]=g[i];
}
else if(f[j]==f[i]+1){
g[j]=(g[j]+g[i])%mod;
}
}
}
ans1=1e9;ans2=0;
for(int j=a1;a[j]+t1-1>=a[a1]&&j>=1;j--){
if(f[j]<ans1){
ans1=f[j];
ans2=g[j];
}
else if(ans1==f[j]){
ans2=(ans2+g[j])%mod;
}
}
printf("%lld %lld\n",ans1,ans2);
}
return 0;
}
最小删除次数使子串消失
文章讲述了如何解决一个字符串问题,给定两个非空字符串s和t,目标是最小次数删除s中的t,使得s中不再包含t。通过暴力求解位置和状态转移数组f和g,计算最小删除次数及其方案数,时间复杂度为O(n*m+n^2),其中n和m分别是s和t的长度。
8355

被折叠的 条评论
为什么被折叠?



