2406 Power Strings(next陣列妙用+字尾陣列)
阿新 • • 發佈:2018-12-24
Power Strings
Each test case is a line of input representing s, a string of printable characters. The length of s will be at least 1 and will not exceed 1 million characters. A line containing a period follows the last test case.
Description
Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc" and b = "def" then a*b = "abcdef". If we think of concatenation as multiplication, exponentiation by a non-negative integer is defined in the normal way: a^0 = "" (the empty string) and a^(n+1) = a*(a^n).Input
Output
For each s you should print the largest n such that s = a^n for some string a.Sample Input
abcd aaaa ababab .
Sample Output
1 4 3
Hint
This problem has huge input, use scanf instead of cin to avoid time limit exceed.題意:問你字串最多有多少個迴圈節
解題思路:next陣列真是巧妙呀!!通過next陣列,很容易計算出迴圈節的長度(N-nxt[N]),然後通過這個長度就能計算出這道題啦!
#include<iostream> #include<deque> #include<memory.h> #include<stdio.h> #include<map> #include<string.h> #include<algorithm> #include<vector> #include<math.h> #include<stack> #include<queue> #include<set> using namespace std; typedef long long int ll; void getNext(char a[],int len,int nxt[]){ nxt[0]=nxt[1]=0; for(int i=1;i<len;i++){ int j=nxt[i]; while(j&&a[i]!=a[j]) j=nxt[j]; nxt[i+1]=(a[i]==a[j])?j+1:0; } } int KMP(char a[],char b[],int N,int M,int nxt[]){ int j=0; int ans=0; for(int i=0;i<N;i++){ while(j&&a[i]!=b[j]) j=nxt[j]; if(a[i]==b[j]) j++; if(j==M){ ans++; } } return ans; } char a[1000050];//原始串 char b[1000050];//模式串 int nxt[1000050]; int N,M; int main(){ while(~scanf("%s",a)){ N=strlen(a); if(a[0]=='.'&&N==1) break; getNext(a,N,nxt); if(N%(N-nxt[N])==0) printf("%d\n",N/(N-nxt[N])); else printf("%d\n",1); } return 0; }
另外還有後綴陣列解法!速度慢很多,但是也是體現了一個很重要的字尾陣列的思想。詳見程式碼理解。另外,倍增超時。
#include <iostream>
#include <deque>
#include <stdio.h>
#include <map>
#include <string.h>
#include <algorithm>
#include <vector>
#include <math.h>
#include <stack>
#include <queue>
#include <set>
using namespace std;
typedef long long int ll;
const int MAXN = 3000005; //用DC3要開三倍大小
int wa[MAXN], wb[MAXN], wv[MAXN], JS[MAXN]; //計算SA用的輔助陣列
int rk[MAXN], height[MAXN], SA[MAXN]; //三個常用陣列
/***字尾陣列倍增解法***/
int cmp(int *r, int a, int b, int l)
{
return r[a] == r[b] && r[a + l] == r[b + l];
}
void DA(int *r, int *SA, int n, int m)
{
int i, j, p, *x = wa, *y = wb, *t;
for (i = 0; i < m; i++)
JS[i] = 0;
for (i = 0; i < n; i++)
JS[x[i] = r[i]]++;
for (i = 1; i < m; i++)
JS[i] += JS[i - 1];
for (i = n - 1; i >= 0; i--)
SA[--JS[x[i]]] = i;
for (j = 1, p = 1; p < n; j *= 2, m = p)
{
for (p = 0, i = n - j; i < n; i++)
y[p++] = i;
for (i = 0; i < n; i++)
if (SA[i] >= j)
y[p++] = SA[i] - j;
for (i = 0; i < n; i++)
wv[i] = x[y[i]];
for (i = 0; i < m; i++)
JS[i] = 0;
for (i = 0; i < n; i++)
JS[wv[i]]++;
for (i = 1; i < m; i++)
JS[i] += JS[i - 1];
for (i = n - 1; i >= 0; i--)
SA[--JS[wv[i]]] = y[i];
for (t = x, x = y, y = t, p = 1, x[SA[0]] = 0, i = 1; i < n; i++)
x[SA[i]] = cmp(y, SA[i - 1], SA[i], j) ? p - 1 : p++;
}
return;
}
/*******************/
/***字尾陣列DC3解法***/
#define F(x) ((x) / 3 + ((x) % 3 == 1 ? 0 : tb))
#define G(x) ((x) < tb ? (x)*3 + 1 : ((x)-tb) * 3 + 2)
int c0(int *r, int a, int b)
{
return r[a] == r[b] && r[a + 1] == r[b + 1] && r[a + 2] == r[b + 2];
}
int c12(int k, int *r, int a, int b)
{
if (k == 2)
return r[a] < r[b] || r[a] == r[b] && c12(1, r, a + 1, b + 1);
else
return r[a] < r[b] || r[a] == r[b] && wv[a + 1] < wv[b + 1];
}
void sort(int *r, int *a, int *b, int n, int m)
{
int i;
for (i = 0; i < n; i++)
wv[i] = r[a[i]];
for (i = 0; i < m; i++)
JS[i] = 0;
for (i = 0; i < n; i++)
JS[wv[i]]++;
for (i = 1; i < m; i++)
JS[i] += JS[i - 1];
for (i = n - 1; i >= 0; i--)
b[--JS[wv[i]]] = a[i];
return;
}
void DC3(int *r, int *SA, int n, int m)
{
int i, j, *rn = r + n, *SAn = SA + n, ta = 0, tb = (n + 1) / 3, tbc = 0, p;
r[n] = r[n + 1] = 0;
for (i = 0; i < n; i++)
if (i % 3 != 0)
wa[tbc++] = i;
sort(r + 2, wa, wb, tbc, m);
sort(r + 1, wb, wa, tbc, m);
sort(r, wa, wb, tbc, m);
for (p = 1, rn[F(wb[0])] = 0, i = 1; i < tbc; i++)
rn[F(wb[i])] = c0(r, wb[i - 1], wb[i]) ? p - 1 : p++;
if (p < tbc)
DC3(rn, SAn, tbc, p);
else
for (i = 0; i < tbc; i++)
SAn[rn[i]] = i;
for (i = 0; i < tbc; i++)
if (SAn[i] < tb)
wb[ta++] = SAn[i] * 3;
if (n % 3 == 1)
wb[ta++] = n - 1;
sort(r, wb, wa, ta, m);
for (i = 0; i < tbc; i++)
wv[wb[i] = G(SAn[i])] = i;
for (i = 0, j = 0, p = 0; i < ta && j < tbc; p++)
SA[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++];
for (; i < ta; p++)
SA[p] = wa[i++];
for (; j < tbc; p++)
SA[p] = wb[j++];
return;
}
/***********************/
//計算rank和height陣列
void calheight(int *r, int *SA, int n)
{
// memset(height,0,sizeof(height));
// memset(rk,0,sizeof(rk));
int i, j, k = 0;
for (i = 1; i <= n; i++)
rk[SA[i]] = i;
for (i = 0; i < n; height[rk[i++]] = k)
for (k ? k-- : 0, j = SA[rk[i] - 1]; r[i + k] == r[j + k]; k++)
;
}
int N; //字串長度
int str[MAXN]; //主字串
char cc[MAXN];
int main()
{
while (~scanf("%s", cc))
{
if(cc[0]=='.')
break;
N = strlen(cc);
for (int i = 0; i < N; i++)
str[i] = int(cc[i]);
str[N] = 0; //必須要末尾補0!!!!!
DC3(str, SA, N + 1, 300); //N是沒有補0的大小,算SA時要把末尾0計算進去,所以要N+1
calheight(str, SA, N); //計算height時不用末尾0
int flag = 0;
for (int i = 1; i <= N/2+1; i++)
{
//三個條件
if (N % i == 0 && rk[0] == rk[i] + 1 && height[rk[0]] == N - i)
{
printf("%d\n", N / i);
flag = 1;
break;
}
}
if (!flag)
printf("1\n");
// for (int i = 0; i <= N; i++)
// cout << SA[i] << " ";
// cout << endl;
// for (int i = 0; i <= N; i++)
// cout << rk[i] << " ";
// cout << endl;
// for (int i = 0; i <= N; i++)
// cout << height[i] << " ";
// cout << endl;
}
return 0;
}