---
# System prepended metadata

title: 'Gọi dp[i][j] là số lần xâu T x'

---

# 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();
}


 
```
:::


