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匹配的子串个数。
备注:
对于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; } /*样例区 */ //------------------------------------------------------------