D K匹配 kmp 区间匹配计算贡献


 链接:https://ac.nowcoder.com/acm/problem/213329
来源:牛客网

题目描述

牛牛是赫赫有名的字符串高手,现在牛牛发现了一种新的匹配方式。给定一个字符串SSS和一个字符串TTT,如果SSS存在一个长度为kkk的子串Sl1,l1+k−1S_{l_1, l_1 + k – 1}Sl1​,l1​+k−1​和TTT的某个长度为kkk的子串Tl2,l2+k−1T_{l_2,l_2 + k – 1}Tl2​,l2​+k−1​相等,那么我们就认为字符串SSS和字符串TTT是kkk匹配的。比如字符串abaccabaccabacc和字符串ddabackkddabackkddabackk就是444匹配的。
牛牛知道这种匹配方式之后就迫不及待的想要提出新的问题。给定一个长度为nnn的字符串SSS和一个长度为kkk的字符串TTT,现在牛牛想知道SSS有多少个子串和TTT是满足kkk匹配的。
本场大样例下载

输入描述:

第一行两个整数n,kn, kn,k分别表示字符串SSS的长度和字符串TTT的长度。
第二行一个长度为nnn的字符串表示SSS。
第三行一个长度为kkk的字符串表示TTT。
保证字符串SSS和TTT中只包含小写字母。

输出描述:

输出一行整数表示SSS中满足和TTT是kkk匹配的子串个数。

示例1

输入

复制

10 2
abaaaababa
ab

输出

复制

33

备注:

对于20%20 /%20%的数据满足1≤k≤n≤5001 /leq k /leq n /leq 5001≤k≤n≤500
对于40%40/%40%的数据满足1≤k≤n≤50001 /leq k /leq n /leq 50001≤k≤n≤5000
对于60%60/%60%的数据满足1≤k≤n≤1e61 /leq k /leq n /leq 1e61≤k≤n≤1e6
对于100%100/%100%的数据满足1≤k≤n≤1e71 /leq k /leq n /leq 1e71≤k≤n≤1e7

分析:

明确题意 k 匹配,是指匹配串在主串的某个子串中被匹配。

所以只要找到每个子串匹配的起点

[i,j] 区间内被匹配,[1,i],[j,n] 区间内的子串也能匹配匹配串

注意当前匹配的子串可能跟上一次被匹配的子串重复,所以左区间从上次匹配的位置i’开始 [i’,i],[j,n] 区间内匹配

注意第一次被匹配,上一次被匹配的位置应该是 0,只要插入一个0就可以了

//-------------------------代码----------------------------

//#define int ll
const int N = 1e7+10;
int n,k;
string s,t;
int nxt[N];

void solve()
{
//    cin>>n>>m;
    cin>>n>>k;;
    cin>>s>>t;
    int lens = s.length(),lent = t.length();
    s = ' ' + s;t = ' ' + t;
    fo(i,2,k) {
        nxt[i] = nxt[i-1];
        while(nxt[i] && t[nxt[i] + 1] != t[i]) nxt[i] = nxt[nxt[i]];
        nxt[i] += (t[nxt[i] + 1] == t[i]);
    }
    V<int> q;
    int j = 1;
    q.push_back(0);
    fo(i,1,n) {
        while(j != 1 && s[i] != t[j])j = nxt[j - 1] + 1;
        if(s[i] == t[j]) j ++ ;
        if(j == lent + 1) {
            q.pb(i - lent + 1);
            j = nxt[j - 1] + 1;
        }
    }
    ll ans = 0;
    int len = q.size() - 1;
//     db(len)
    for(int i = 1;i<=len;i++) {
        int ll = q[i-1],l = q[i];
        int r = l + lent - 1;
//         dbbb(ll,l,r);
        ans += 1ll * (l - ll) * (n - r + 1);
    }
    cout<<ans<<endl;
}

void main_init() {}
signed main(){
    AC();clapping();TLE;
    cout<<fixed<<setprecision(12);
    main_init();
//  while(cin>>n,n)
//  while(cin>>n>>m,n,m)
//    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

 

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/289022.html

(0)
上一篇 2022年9月12日
下一篇 2022年9月12日

相关推荐

发表回复

登录后才能评论