トピックリンク:期間
題名
長さnの文字列sを指定して、各プレフィックスの循環セクションを見つけます。つまり、各i(2≤i≤n)について、最大の整数k> 1(kが存在する場合)を見つけ、Sの最初のi文字で構成される接頭辞が特定の文字列をk回繰り返すことによって得られるようにします。の。Kと対応するKを含むすべてのiを出力します。
回答
MP(最適化されていないKMP)アルゴリズムの適応機能について少し理解していれば、この問題は簡単に解決できます。
不一致関数
f [i]:状態iが一致しない場合に転送される新しい状態。
実際、これは、最初の(i-1)文字の最も長い共通の真の接頭辞と接尾辞の数としても理解できます。
したがって、f配列を取得している場合は、質問に変わります。文字列を指定し、この文字列の最小ループセクションを尋ねます。
-
これは、文字列Tが最小のループセクションsで構成されていると想定して、絵を描くことで得られます。
(ここでiとfi {f_i}に注意してくださいf私文字列は0から始まるため、これは文字列の次のビットです。)
したがって、i = T len、fi = 2 ∗ S len {i = T_ {len}、f_i = 2 * S_ {len}}私=Tl e n、f私=2∗Sl e n
明らかに、最小ループセクション長 = i − fi {i-f_i}を取得できます。私−f私,次数就是 i / ( i − f i ) {i/(i-f_i)} i / (i−f私) -
文字列Tに最小ループセクションがない場合、何をすべきかを尋ねる人もいるかもしれません。(図に示すように)
最小のループ部長さも得られることは言うまでもありませんが、この最小のループ部長さの前提は、ストリングTが無限下向きに配置されていることです。
では、文字列に最小ループセクションがあるかどうかをどのように判断するのでしょうか。
あなたがそれを注意深く考えれば、あなたは得ることができます:
- 如果 i % ( i − f i ) = = 0 {i\%(i-f_i)==0} 私%(私−f私)= =0は、有限文字列に最小のループセクションがあることを意味し、番号は次のとおりです。i /(i − fi){i /(i-f_i)}i / (i−f私)。
- それ以外の場合、最小ループセクションはありません。
コード
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
using namespace std;
//extern "C"{void *__dso_handle=0;}
typedef long long ll;
typedef long double ld;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define pii pair<int,int>
#define lowbit(x) x&-x
const double PI=acos(-1.0);
const double eps=1e-6;
const ll mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=1e6+10;
const int maxm=100+10;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int f[maxn];
void getfail(string s)
{
memset(f, 0, sizeof(f));
f[0]=f[1]=0;
for(int i=1;i<s.length();i++)
{
int j=f[i];
while(j && s[i]!=s[j]) j=f[j];
f[i+1] = (s[i]==s[j]?j+1:0);
}
}
int main()
{
int n;
int cas=0;
while(cin >> n && n)
{
string s;
cin >> s;
getfail(s);
printf("Test case #%d\n",++cas);
for(int i=2;i<=n;i++)
{
if(f[i] && (i%(i-f[i])==0)) printf("%d %d\n",i,i/(i-f[i]));
}
printf("\n");
}
}