Cut Substrings

Cut Substrings

Created by LXC on Mon Feb 12 09:26:40 2024

https://codeforces.com/problemset/problem/1729/G

ranting: 2100

tag: combinatorics, dp, hashing, strings, two pointers

problem

给出两个非空字符串$s$和$t$,以最小次数删除使得字符串$s$中不会出现字符串$t$,每次可以将字符串$s$中所有任意一个字符串$t$删除,并且有多少种不同的的方案,如:删除序列$\lbrace 1,2,3\rbrace $与删除序列$\lbrace 1,2,4\rbrace $是不同的,删除序列$\lbrace 2,4,6\rbrace $和删除序列$\lbrace 2,6\rbrace $也是不同的,但删除序列$\lbrace 3,5\rbrace $与删除序列$\lbrace 5,3\rbrace $是相同的

现有$q$次询问,每次输出最小删除次数与以最小删除次数删除的方案数(对$10^9+7$取模)

程序输入的第一行是询问次数$q(1\le q \le 50 )$,接下来一行字符串$s(1 \le |s| \le 500)$和一行字符串$t(1 \le |t| \le 500)$

程序输出$q$行答案,每次输出最小删除次数与以最小删除次数删除的方案数(对$10^9+7$取模)

solution

预处理匹配位置p,$p_i = 1$时,$t == s_{i-m+1, i}$,否则$p_i = 0$

令$f_i$是前i个字符中最少删除次数,$c_i$为前i个字符中满足最少删除次数的删除方案数。

答案就是$f_i, c_i$。

状态转移

  • 对于$p_i = 1$
    • $f_i = \min f_{j-m}+1$,条件$i-m+1\le j \le i, p_j = 1$
    • $c_i = \sum c_{j-m}$,条件$i-m+1\le j \le i, p_j = 1, f_{j-m} + 1 = f_i$
  • 对于$p_i = 0$
    • $f_i = f_{i-1}$
    • $c_i = c_{i-1}$

code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

#include <bits/stdc++.h>
// #define SINGLE_INPUT
#define ll long long
#define ull unsigned long long
#define N 500005

const ll MOD = 1e9+7;
using namespace std;

template<class t,class u> ostream& operator<<(ostream& os,const pair<t,u>& p) {
return os<<'['<<p.first<<", "<<p.second<<']';
}
template<class t> ostream& operator<<(ostream& os,const vector<t>& v) {
os<<'['; int s = 1;
for(auto e:v) { if (s) s = 0; else os << ", "; os << e; }
return os<<']';
}
template<class t,class u> ostream& operator<<(ostream& os,const map<t,u>& mp){
os<<'{'; int s = 1;
for(auto [x,y]:mp) { if (s) s = 0; else os << ", "; os<<x<<": "<<y; }
return os<<'}';
}

void sol() {
string s, t;
cin >> s >> t;
int n = s.size(), m = t.size();
vector<int> p(n+1);
for (int i=m; i<=n; i++) {
if (s.substr(i-m, m) == t) p[i] = 1;
}
vector<ll> f(n+1, MOD), c(n+1);
f[0] = 0; c[0] = 1;
for (int i=1; i<=n; i++) {
if (p[i]) {
for (int j=i-m+1; j<=i; j++) {
if (p[j]) f[i] = min(f[i], f[j-m]+1);
}
for (int j=i-m+1; j<=i; j++) {
if (p[j] && f[j-m]+1 == f[i]) c[i] = (c[i] + c[j-m]) % MOD;
}
} else {
f[i] = f[i-1];
c[i] = c[i-1];
}
}
cout << f[n]%MOD << " " << c[n] << "\n";
}

int main() {
cout << setprecision(15) << fixed;
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifndef SINGLE_INPUT
int t;
cin >> t;
while (t--) {
sol();
}
#else
sol();
#endif
return 0;
}