KMP

\(s\) (长串)叫文本串,\(t\)(短串)叫模式串。

\(next_i\):在 \(p\) 中以 \(p[i]\) 结尾的后缀能够匹配的从 \(0\) 开始非平凡前缀的最大长度。

为什么这样做?考虑尝试的时候有顺序地做,只有这个顺序有道理。

P3375

这里字符串以 \(0\) 开始。注意 \(next_i\) 实际上是字符串中前缀的长度,也即前缀的结尾坐标往右一位

并且你尝试匹配的时候,是从 \(next_{i - 1}\),也就是已经相等的字符串的后一位,看看是否与新加入的字符相等。之后也都是找到的是后一位

写 KMP 的时候,脑子不能胡。

#include<bits/stdc++.h>
using namespace std;
#define f(i, a, b) for(int i = (a); i <= (b); i++)
#define cl(i, n) i.clear(),i.resize(n);
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 1e9;
string s, t;
int nxt[1000010];
int main() {
    ios::sync_with_stdio(0);
    cin.tie(NULL);
    cout.tie(NULL);
    cin >> s >> t;
    int n = s.size(), m = t.size();
    for(int i = 1, j = 0; i < m; i++) {
        while(j >= 1 && t[i] != t[j])j = nxt[j - 1];
        if(t[i] == t[j]) j++;
        cout << i << " " << j << endl;
        nxt[i] = j;
    }
    for(int i = 0, j = 0; i < n; i++) {
        while(j >= 1 && t[i] != t[j])j = nxt[j - 1];
        if(t[i] == t[j]) j++;
        if(j == m) {
            cout << i - m + 2 << endl;
            j = nxt[j - 1]; 
        }
    }
    f(i, 0, m - 1) cout << nxt[i] << " \n"[i == m];
    return 0;
}
CF808G

【题意】给定字符串 \(s,t\)\(s\) 包含小写字母和问号,\(t\) 包含小写字母。求将所有 \(s\) 中问号改成任意字母的方案中,\(t\)\(s\) 中出现最多次的方案。

【分析】考虑 DP。令 \(dp_{i,j}\) 表示 \(s_i\) 匹配 \(t_j\) 的最大匹配次数(是老套路了)。如遇到字母怎么办?

考虑枚举字母变成了什么。对于一个确定的字母,我们转移到一个最大的 \(k\),使得 \(s_{i + 1} = t_k\)。这为什么是对的呢?考虑反例类似这样:\(\mathtt{ababa?abacd; ababacd}\)。这时候问号应该匹配 \(t\) 的第二个字符。因为如果匹配上的是第四个字符,那么之后无法匹配 \(b\)。但是我们在之后发现,\(b\) 无法匹配的时候,会向下找能匹配的,也就是和之前匹配第二个字符是一样的效果。容易发现,不论是哪一个方案,如果它后面的方案都不能用的话,它一定能用上。因此每次找最大转移这个方案向下兼容,覆盖了所有方案。

那么向下兼容的应用场景是什么?考虑不同的字符之间能不能这样贪心。依然考虑上述的例子。如果问号处填 \(c\),那么是比 \(b\) 局部更优的方案。之后失配的时候,我们尝试换成 \(b\),是把 \(ababac+a\) 跳转到 \(abab+a\)。但是这时候我们发现,由于 \(ababa\) 不等于 \(abaca\)(因为问号处的 \(c\) 应该是 \(b\))切换不过来,因此没办法兼容。

预处理 \(jump_{i, c}\) 表示 \(t_{1,...,i} + c\)\(c\) 是一个字符)也就是失配指针。

时间复杂度 \(O(26nm)\),但是我不太会写预处理,于是加上了 \(O(m^2)\)(其实是应该做到 \(O(26m)\) 的)但是特判以下问题不大。

mine O(26nm+m^2)

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define f(i, a, b) for(int i = (a); i <= (b); i++)
#define cl(i, n) i.clear(),i.resize(n);
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 1e9;
void cmax(int &x, int y) {if(x < y) x = y;}
void cmin(int &x, int y) {if(x > y) x = y;}
int nxt[100010];
int jump[100010][26];
vector<int> bd[100100];
vector<vector<int>> dp;
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(NULL);
    cout.tie(NULL);
    //time_t start = clock();
    //think twice,code once.
    //think once,debug forever.
    string s, t; cin >> s >> t; 
    int n = s.size(), m = t.size();if(n < m) {cout << 0 << endl; return 0;}
    dp.resize(n + 2);
    memset(jump, -1, sizeof(jump));
    f(i, 0, n + 1) dp[i].resize(m + 2);
    for(int i = 1, j = 0; i < m; i ++) {
        while(t[i] != t[j] && j > 0) j = nxt[j - 1];
        if(t[i] == t[j]) {
            nxt[i] = j + 1;
            j ++;
        }
    }
 //   f(i, 0, m) cout << nxt[i];
 //   cout << endl;
    
    for(int i = 1; i <= m; i ++) {
        
        int j = nxt[i - 1];
        while(j > 0) {
            int k = t[j];
            if(jump[i][k - 'a'] < j) {
                jump[i][k - 'a'] = j;
                bd[i].push_back(j);
            }
            j = nxt[j - 1];
        }
        
        int k = t[j];
        if(jump[i][k - 'a'] < j) {
            jump[i][k - 'a'] = j;
            bd[i].push_back(j);
        }        
    }
//    if(s.substr(0, 4) == "eeio") {return 0;}
//    cout << n << endl;
  //  f(i, 0, m - 1) cout << nxt[i] << " \n"[i == m - 1];
 //   f(i, 0, m) f(k, 0, 25) cout << jump[i][k] << " \n"[k == 25];
//    memset(dp, 0x3f, sizeof(dp));
//    fill(dp.begin(), dp.end(), 0x3f3f3f3f);
 //   
    s += "?";
    f(i, 0, n + 1) f(j, 0, m + 1) dp[i][j] = -inf;
    int ans = 0;
    dp[0][0] = 0;
    for(int i = -1; i <= n; i ++) {
        for(int j = -1; j < m; j ++) {
        //    cout << i << " " << j << " " << dp[i + 1][j + 1] << endl;
            
            cmax(ans, dp[1 + i][1 + j]);if(i == n) continue;
            if(s[i + 1] == '?') {
            //    for(char k = 'a'; k <= 'z'; k ++) {
                //    if(s[i + 1] != '?' && s[i + 1] != k) continue;
                if(j < m - 1) cmax(dp[1 + i + 1][1 + j + 1], dp[1 + i][1 + j]);
                for(int k : bd[j + 1]){
                //    if(j < m - 1 && k == t[j + 1]) 
                    //else 
                    cmax(dp[1 + i + 1][1 + k], dp[1 + i][1 + j] + (j == m - 1));
                }
            }
            else {
                char k = s[i + 1];
                if(j < m - 1 && k == t[j + 1]) cmax(dp[1 + i + 1][1 + j + 1], dp[1 + i][1 + j]);
                else cmax(dp[1 + i + 1][1 + jump[j + 1][k - 'a']], dp[1 + i][1 + j] + (j == m - 1));
            }
        }
    }
    cout << ans << endl;
    //time_t finish = clock();
    //cout << "time used:" << (finish-start) * 1.0 / CLOCKS_PER_SEC <<"s"<< endl;
    return 0;
} 

julao O(26nm + 26m)

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define f(i, a, b) for(int i = (a); i <= (b); i++)
#define cl(i, n) i.clear(),i.resize(n);
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 1e9;
void cmax(int &x, int y) {if(x < y) x = y;}
void cmin(int &x, int y) {if(x > y) x = y;}
int nxt[100010];
int jump[100010][26];
vector<int> bd[100100];
vector<vector<int> > dp;
signed main()
{
//	freopen("1.in","r",stdin);
    ios::sync_with_stdio(0);
    cin.tie(NULL);
    cout.tie(NULL);
    string s, t; cin >> s >> t; 
    int n = s.size(), m = t.size();
//	if(n < m) {cout << 0 << endl; return 0;}
    dp.resize(n + 2);
    memset(jump, -1, sizeof(jump));
    f(i, 0, n + 1) dp[i].resize(m + 2);
    for(int i = 1, j = 0; i < m; i ++) {
        while(t[i] != t[j] && j > 0) j = nxt[j - 1];
        if(t[i] == t[j])j ++;
        nxt[i] = j;
    }
    t+='?';
    for(int i=0;i<m+1;i++)
		for(int j=0;j<26;j++)
			if(i&&t[i]-'a'!=j) jump[i][j]=jump[nxt[i-1]][j];
            else
			{
                if (t[i]-'a'==j) jump[i][j]=i+1;
                else jump[i][j]=i;
            }
    f(i, 0, n ) f(j, 0, m) dp[i][j] = -inf;
    int ans = 0;
    dp[0][0] = 0;
    for(int i=0;i<n;i++)
        for(int j=0;j<m+1;j++)
            if(s[i]!='?') cmax(dp[i+1][jump[j][s[i] - 'a']],dp[i][j]+(jump[j][s[i] - 'a'] == m));
            else
			{
                for(int k=0;k<26;k++) cmax(dp[i+1][jump[j][k]],dp[i][j]+(jump[j][k]==m));
            }
//    for(int i=0;i<n;i++,puts("")) for(int j=0;j<m;j++) printf("%d ",dp[i][j]);
    for(int i=0;i<m+1;i++) cmax(ans,dp[n][i]);
    cout << ans << endl;
    return 0;
}
/*
winlose???winl???w??
win
*/

posted @ 2022-07-09 23:04  OIer某罗  阅读(21)  评论(0编辑  收藏  举报