HDu 6153 a secret 扩展KMP模板

版权声明:那个,最起码帮我加点人气吧,署个名总行吧 https://blog.csdn.net/qq_41670466/article/details/83308477

题意大致就是给你两个串,然后让你求第二个串的各个后缀在第一个串的出现次数,然后让次数乘该后缀的长度累加输出,最后结果是对1e9+7取模

思路:在讲具体思路之前,如果对扩展kmp不了解或者没听说过的话,建议先看看这个博客https://blog.csdn.net/dyx404514/article/details/41831947

回归正题:我们首先要对这个问题进行转换,因为在我所学过的算法中大都是对前缀进行处理,这样也符合串的输入顺序,所以首先需要对两个串进行反转,这样求串2的后缀就变成了串2的前缀,于是问题就转换为求转换过后的串2的各前缀在串1出现的次数和长度的乘积累加和,进一步分析就需要解决这个乘积的问题,很明显单纯的先计算出现次数然后再乘再累加一定会超时的,所以就需要对这个问题再进行转换,这里使用的方法就是计算串1的连续字串在串2的相同前缀数,如果求得串1在第1个位置开始的连续字串跟串2相同的前缀是3,那么就代表串2的前三个字符在串1出现,然后这个三就包括a,aa,aaa,(假设前三个字符是aaa),那么先计算这个三个的乘积累加,很明显是一个等差数列:1*1+1*2+1*3,如果后续又出现这几个字串,那么在加就好,反正乘积就是加法的累计。其余的细节就是扩展kmp了,在这里不在细讲,上面的连接里说的很详细

代码:

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<cstdlib>
#include<algorithm>

using namespace std;

const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
int nxt[maxn];
int ex[maxn];
string s, s1;

inline long long add(long long n)
{
		long long ans = ((n%mod)*((n + 1) % mod) / 2) % mod;
		return ans;
}

void  getnxt()
{
		int len = s1.size();
		int j = 0, k = 1;
		nxt[0] = len;
		while (j + 1 < len&&s1[j + 1] == s1[j])	j++;
		nxt[1] = j;
		for (int i = 2; i < len; i++)
		{
				int p = nxt[k] + k - 1;
				int L = nxt[i - k];
				if (i + L < p + 1)
						nxt[i] = L;
				else
				{
						j = max(0, p - i + 1);
						while (i + j < len&&s1[i + j] == s1[j])
								j++;
						nxt[i] = j;
						k = i;
				}
		}
}

void exkmp()
{
		int len = s.size(), len2 = s1.size();
		getnxt();
		int j = 0, k = 0;
		while (j < len&&j < len2&&s[j] == s1[j]) j++;
		ex[0] = j;
		for (int i = 1; i < len; i++)
		{
				int p = ex[k] + k - 1;
				int L = nxt[i - k];
				if (i + L < p + 1)
						ex[i] = L;
				else
				{
						j = max(0, p - i + 1);
						while (i + j < len&&j < len2&&s[i + j] == s1[j]) 		j++;
						ex[i] = j;
						k = i;
				}
		}
}

void ini()
{
		memset(nxt, 0, sizeof(nxt));
		memset(ex, 0, sizeof(ex));
		s.clear();
		s1.clear();
}

int main()
{
		ios::sync_with_stdio(false);
		int t;
		cin >> t;
		while (t--)
		{
				ini();
				cin >> s >> s1;
				int len = s.size();
				reverse(s.begin(), s.end());
				reverse(s1.begin(), s1.end());
				exkmp();
				long long ans = 0;
				for (int i = 0; i < len; i++)
				{
						if (ex[i])
								ans = (ans + add(ex[i]) % mod) % mod;
				}
				cout << ans % mod << endl;
		}
		//system("pause");
		return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41670466/article/details/83308477