Power Strings——一个字符串由一个子串重复n次形成,求n的最大值

Given two strings a and b we define ab to be their concatenation. For example, if a = “abc” and b = “def” then ab = “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
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.
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

我们可以发现当一个串由长度为i的子串循环组成时

1: rank[0] = rank[i] + 1

2: len % i == 0

3: heig[rak[0]] == len - i
此题用倍增法会超时,所以要用dc3


#include<cstdio>
#include<algorithm>
#include<queue>
#include<iostream>
#include<cmath>
#include<cstring>
typedef long long ll;
using namespace std;
#define F(x) ((x)/3+((x)%3==1?0:tb))
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
const int MAXN = 3000000;//n*10
int sa[MAXN];
int rk[MAXN];
int height[MAXN];
ll n;
char s[MAXN];
int r[MAXN];
int wa[MAXN], wb[MAXN], wv[MAXN];
int wws[MAXN];
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++) wws[i] = 0;
	for (i = 0; i < n; i++) wws[wv[i]]++;
	for (i = 1; i < m; i++) wws[i] += wws[i - 1];
	for (i = n - 1; i >= 0; i--) b[--wws[wv[i]]] = a[i];
	return;
}
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 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;
}
void calheight(int *r, int *sa, int n)
{
	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);
	return;
}
int main()
{
	//freopen("shuru.txt", "r", stdin);
	while (scanf("%s", s)==1&&s[0]!='.') {
		int Max = -1;
		n = strlen(s);
		for (int i = 0; i < n; i++) {
			r[i] = s[i];
			if (r[i] > Max)Max = r[i];
		}
		r[n] = 0;
		dc3(r, sa, n + 1, Max + 1);
		calheight(r, sa, n);
		bool flag = 0;
		for (ll i = 1; i <= n; i++) {
			if (n%i == 0 && rk[0] == rk[i] + 1 && height[rk[0]] == n - i)
			{
				flag = 1;
				printf("%lld\n", n / i);
				break;
			}
		}
		if (flag == 0)printf("1\n");
	}
	return 0;
}
/*
	之前一直用倍增法,发现有些题目卡倍增法,而DC3却能AC,所以顺便弄了
	提一些注意点:1.MAXN开n的十倍大小;
				  2.dc3(r,sa,n+1,Max+1);r为待后缀处理的数组,sa为存储排名位置的数组,n+1和Max+1 都和倍增一样
				  3.calheight(r,sa,n);和倍增一样
				  *n   = 8;
*num[]   = { 1, 1, 2, 1, 1, 1, 1, 2, $ };注意num最后一位为0,其他大于0
*rank[]  = { 4, 6, 8, 1, 2, 3, 5, 7, 0 };rank[0~n-1]为有效值,rank[n]必定为0无效值
*sa[]    = { 8, 3, 4, 5, 0, 6, 1, 7, 2 };sa[1~n]为有效值,sa[0]必定为n是无效值
*height[]= { 0, 0, 3, 2, 3, 1, 2, 0, 1 };height[2~n]为有效值

*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值