# 7A Điền xâu
Ta sẽ điền cho từng vị trí $1,2..n$.
Nhận thấy : Để tạo thành xâu $T$, thì ta cần phải tạo thành các tiền tố độ dài $1,2..|T|$.
Gọi $dp[i][j]$ là số lần xâu $T$ xuất hiện nhiều nhất khi ta đã điền tới kí tự thứ $i$ và đoạn $[i-j+1..j]$ là $1$ tiền tố của xâu $T$.
Vậy khi điền tới $i$, ta cần biết nếu ta điền ở vị trí $i+1$ $1$ kí tự $j$ nào đó, thì độ dài tiền tố lớn nhất trong xâu $T$ mà ta đã tạo được tới $i+1$ là bao nhiêu.
Vậy ta cần quản lý thông tin này trong một mảng $next[i][j]$.
Ta sẽ xây mảng $next$ như sau :
- Nếu $T[i+1] = j$ thì $next[i][j] = i +1$.
- Nếu không thì $next[i][j] = next[KMP[i]][j]$. Ở đây $KMP[i]$ chính là $max(i-j)$ với mọi $j > 1$ sao cho $T[j..i]$ là $1$ tiền tố của $T$. Ta có thể tính được bằng cách dùng thuật toán KMP hoặc Zfuction (ở đây tác giả sử dụng Zfunction).
Ta có : $dp[next[j][a[i+1]]][j] = max (dp[next[j][a[i+1]]][j], dp[i][j] + (next[j][a[i+1]] == n))$
Đáp án chính là $max(dp[n][i])$ với $(i \le |T|)$.
:::spoiler Code mẫu
```cpp
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define fi first
#define sc second
#define pll pair<ll,ll>
#define pii pair<int,int>
#define all(x) (x).begin(),(x).end()
#define TASK "main"
const int nmax = 1e5 + 7;
int f[nmax][26];
vector<int> dp[nmax];
int z[nmax];
vector<int> toer[nmax];
int g[nmax];
string s;
string t;
void solve(){
cin >> s >> t;
int l = 0,r = 0;
z[0] = 1;
for(int i = 1 ;i<t.size();++i){
z[i] = min(z[i-l], r-i +1);
r=max(r,i);
if(t[i] == t[0]) z[i] = max(z[i], 1);
while(i + z[i] -1 ==r && i + z[i] - 1 < t.size() && t[i+z[i]] == t[z[i]]){
++z[i];
++r;
l= i;
}
}
set<int> se;
for(int i =0;i<t.size();++i){
se.insert(i);
toer[i+z[i]].push_back(i);
for(auto x: toer[i]){
se.erase(se.find(x));
}
if(se.size()){
g[i] = i - *se.begin() + 1;
}
}
for(int i = 0 ;i<=s.size();++i){
dp[i].resize(t.size() + 3,-1);
}
dp[0][0] = 0;
if(t[0] == s[0] || s[0] == '?') dp[0][1] = 1 == t.size();
// for(int i =0;i<t.size();++i) cout << g[i] << ' ';
int ans = 0;
for(int i = 0;i<s.size() ;++i){
for(int j = t.size();j>=0;--j){
if(dp[i][j] == -1) continue;
if(j>0)
dp[i][g[j-1]] = max(dp[i][g[j-1]],dp[i][j]);
ans = max(ans, dp[i][j]);
if(s[i+1] == '?'){
for(int c = 0;c<26;++c){
if((char)('a' + c) == t[j]){
dp[i+1][j+1] = max(dp[i+1][j+1], dp[i][j] + (j+1 == t.size()));
} else dp[i+1][0] = max(dp[i+1][0],dp[i][j]);
}
} else {
if(s[i+1] == t[j]){
dp[i+1][j+1] = max(dp[i+1][j+1], dp[i][j] + (j+1 == t.size()));
} else dp[i+1][0] = max(dp[i+1][0],dp[i][j]);
}
dp[i][0] = max(dp[i][0], dp[i][j]);
}
}
cout << ans << '\n';
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
if(fopen(TASK ".inp","r")){
freopen(TASK ".inp","r",stdin);
freopen(TASK ".out","w",stdout);
}
solve();
}
```
:::