J-文字列を数える(kmp)

AekdyCoinは、数論の問題だけでなく、文字列の問題にも優れていることはよく知られています。文字列sを指定すると、この文字列の空でないプレフィックスをすべて書き留めることができます。次に例を示します
。s:「abab」
プレフィックスは次のとおりです。「a」、「ab」、「aba」、「abab」
プレフィックスごとに、sで一致する回数をカウントできます。したがって、接頭辞「a」が2回一致し、「ab」も2回一致し、「aba」が1回一致し、「abab」が1回一致することがわかります。ここで、すべてのプレフィックスの一致時間の合計を計算するように求められます。「abab」の場合、2 + 2 + 1 + 1 = 6です
。答えは非常に大きい可能性があるため、答えmod10007を出力します。

入力

最初の行は単一の整数Tで、テストケースの数を示します。
いずれの場合も、最初の行は整数n(1 <= n <= 200000)であり、これは文字列sの長さです。文字列sを与える行が続きます。文字列内の文字はすべて小文字です。

出力

いずれの場合も、1つの数値のみを出力します。smod10007のすべてのプレフィックスの一致時間の合計です。

サンプル入力

1
4
abab

サンプル出力

6

文字列内の各プレフィックスの出現回数をカウントし、合計する

文字列をトラバースし、各位置で次の値をバックトラックします。バックトラックするたびに、プレフィックスが後で表示されることを意味します。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5; 

char a[N], b[N];
int Next[N], f[N]; // Next是字符串 a 和自己匹配,f是字符串 a 和 b 匹配 
int n, m;
// 求解 Next 数组
void get_next()
{
    
    
	Next[1] = 0;
	for (int i = 2, j = 0; i <= n; i++) {
    
    
		while (j > 0 && a[i] != a[j + 1]) j = Next[j];
		if (a[i] == a[j + 1]) j++;
		Next[i] = j;
	}
}

void kmp()
{
    
    
	for (int i = 1, j = 0; i <= m; i++) {
    
    
		while (j > 0 && (j == n || b[i] != a[j + 1])) j = Next[j];
		if (b[i] == a[j + 1]) j++;
		f[i] = j;
		// if (f[i] == n) 此时就是 A 在 B 中的某一次出现 
	}
}

int main(void)
{
    
    
	int t, res, tt;
	cin >> t;
	while (t--) {
    
    
		scanf("%d", &n);
		res = n;
		scanf("%s", a + 1);
		get_next();
		for (int i = 1; i <= n; i++) {
    
    
			tt = Next[i];
			while (tt != 0) {
    
    
				res++;
				tt = Next[tt];
			}
			res %= 10007;
		} 
		printf("%d\n", res);
	}
	
	return 0;
}

おすすめ

転載: blog.csdn.net/weixin_43772166/article/details/108784482