ディレクトリ
(次のアレイKMPで使用される)文字列を数えます
タイトル
よくAekdyCoinは、文字列の問題だけでなく、数論の問題が得意であることが知られています。文字列sを与えられたとき、私たちはこの文字列のすべての非空の接頭辞を書き留めることができます。例:
S:「ABAB」
プレフィックスは、以下のとおりです。「A」、「AB」、「ABA」、「ABAB」
各プレフィックスに対して、我々はそれがSに一致した回数をカウントすることができます。だから我々は、その接頭辞を見ることができる「」、二回一致した「AB」はあまりにも二回一致し、「ABA」は一度一致し、「ABABは」一回一致します。今、あなたはすべてのプレフィックスの一致回数の合計を計算するように求められます。「ABAB」のために、それは2 + 2 + 1 + 1 = 6
答えは非常に大きくてもよいので、出力応答MOD 10007
入力
最初の行は、単一の整数、Tは、テストケースの数を示す、です。
各場合について、最初の行は、文字列sの長さであり、整数n(1 <= N <= 200000)です。行は、文字列sを与え、次の。文字列内の文字はすべて小文字です。
出力
それぞれの場合について、出力つのみ番号:S MOD 10007のすべてのプレフィックスに一致する時間の合計
サンプル入力
1
4
ABABの
サンプル出力
6
問題の意味
文字列を指定すると、すべてのプレフィックスの数は、文字列で表示されます取得し、接頭辞自体が考えられます。
考え
問題を解決するに読む
、と言うタイトルである第1、すべてのを次のアレイを使用するには、その後、これを言う:時々 、他の文字列をKMPを検索するために、検索、次の最適化の小さな配列をスピードアップするだろう次の配列を計算するとき。
以下:
//优化前
while (j < len)
{
if (i == -1 || str[i] == str[j])
nex[++j] = ++i;
else
i = nex[i];
}
}
//====================================
//优化后
while (j < len)
{
if (i == -1 || str[i] == str[j])
{
if (str[++i] == str[++j])
nex[j] = nex[i];
else
nex[j] = i;
}
else
i = nex[i];
}
}
しかし、時にはタイトルなどの次のアレイ、後に使用される何の最適化はありません。
トピック・ソリューションは、次の配列との関係を作成し、次の時間は、あなたが文字列を探している、前があったことを証明した、バッククエリの配列を使用します
あなたはバックトラックの発生回数に基づいて算出することができるようになっています。
例えば、のタイトル
序号 0 1 2 3 4
字符串 a b a b
next -1 0 0 1 2
J = 1、1バック和+ = 1から開始し、J = 2初めて、和+ = 1、J =で 3 回、それぞれバック、及びJ = 4、の和+ = 2、和+ = 2。
したがって、6回の合計。(再印刷)
ここで説明する:
例えば、シリアル番号4 B。2再び第1時間、次いで0、及び、合計+ = 2。最初のプラスは、「AB」があります。第二のプラスは「ABAB」です。
モジュロすることを忘れないでください。
問題の解決策
#include <iostream>
#include <cstring>
#define N 200077
using namespace std;
char str[N];
int nex[N];
int len;
void getNext()
{
int i = -1, j = 0;
nex[0] = -1;
while (j < len)
{
if (i == -1 || str[i] == str[j])
nex[++j] = ++i;
else
i = nex[i];
}
}
int main()
{
int T;
cin >> T;
while (T--)
{
cin >> len;
cin >> str;
getNext();
int res = 0;
for (int i = 1; i <= len; i++)
{
int p = nex[i];
while (p!=-1)
{
res++;
p = nex[p];
}
}
cout<<res%10007<<endl;
}
}