POJ - 2406 Power Strings

1.題面

http://poj.org/problem?id=2406

2.題意

已知一個字符串s是由某個串t經過n重複形成的

現在給你s希望你求出n最大可以是多少

3.思路

這道題用後綴數組的倍增算法寫居然會超時,不得套了一個DC3算法,總算過了。

然而即使使用了DC3算法程序的運行時間依舊高達2.5ms

正解應該是kmp算法,沒關係,有空我再補上。

用後綴數組有兩種寫法

第一種是羅穗蹇在他的pdf中介紹的,建立好height數組後,枚舉t的長度k,k能整除s的長度那是必須的,除此意外要求Suffix(0+k)與Suffix(0)的最長公共前綴長度爲n-k,因爲從小到大枚舉k所以找到一個合法的k之後就可以直接輸出結果了

第二種和第一種差不多,慢了200+ms,沒什麼好說的,直接貼在下面了

4.代碼

/*****************************************************************
    > File Name: Cpp_Acm.cpp
    > Author: Uncle_Sugar
    > Mail: [email protected]
    > Created Time: 2016年07月30日 星期六 21時03分33秒
*****************************************************************/
# include <cstdio>
# include <cstring> 
# include <cctype>
# include <cmath>
# include <cstdlib>
# include <climits>
# include <iostream>
# include <iomanip>
# include <set>
# include <map>
# include <vector>
# include <stack>
# include <queue>
# include <algorithm>
using namespace std;

# define rep(i,a,b) for (i=a;i<=b;i++)
# define rrep(i,a,b) for (i=b;i>=a;i--)

template<class T>void PrintArray(T* first,T* last,char delim=' '){ 
	for (;first!=last;first++) cout << *first << (first+1==last?'\n':delim); 
}

const int debug = 1;
const int size  = 10 + 3000000; 
const int INF = INT_MAX>>1;
typedef long long ll;

const int MAXN = 3000000 + 100;
#define F(x) ((x)/3+((x)%3==1?0:tb))
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
int wa[MAXN*3],wb[MAXN*3],wv[MAXN*3],wss[MAXN*3];
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++)wss[i] = 0;
	for(i = 0;i < n;i++)wss[wv[i]]++;
	for(i = 1;i < m;i++)wss[i] += wss[i-1];
	for(i = n-1;i >= 0;i--)
		b[--wss[wv[i]]] = a[i];
}
void dc3(int *r,int *sa,int n,int m)
{
	int i, j, *rn = r + n;
	int *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++];
}
//str和sa也要三倍
void da(int str[],int sa[],int rank[],int height[],int n,int m)
{
	for(int i = n;i < n*3;i++)
		str[i] = 0;
	dc3(str, sa, n+1, m);
	int i,j,k = 0;
	for(i = 0;i <= n;i++)rank[sa[i]] = i;
	for(i = 0;i < n; i++)
	{
		if(k) k--;
		j = sa[rank[i]-1];
		while(str[i+k] == str[j+k]) k++;
		height[rank[i]] = k;
	}
}
int str[size], sa[size], rank[size], height[size];
char s[1000000+10];

void Debug(int n){
	for (int i=1;i<=n;i++){
		cout << "* " << i << "*\t" << height[i] << "\t";
		PrintArray(str+sa[i],str+n);
	}
	for (int i=0;i<n;i++){
		cout << i << (i==n-1?'\n':'\t');
	}
	for (int i=0;i<n;i++){
		cout << rank[i] << (i==n-1?'\n':'\t');
	}
	cout << endl;
}

int n,k;	
int table[size];

int main()
{
	//# std::ios::sync_with_stdio(false);cin.tie(0);
	int i,j;
	while (~scanf("%s",s)){
		if (*s=='.') break;
		//# void da(int str[], int sa[] ,int rank[] ,int height[], int n, int m){
		for (i=0;s[i];i++){
			str[i] = s[i];
		}
		n = i;
		da(str,sa,rank,height,n,300);

		//# Debug(n);
		table[rank[0]] = n;
		for (i=rank[0]+1;i<=n;i++)
			table[i] = min(table[i-1],height[i]);
		for (i=rank[0]-1;i>=0;i--)
			table[i] = min(table[i+1],height[i+1]);
	/*	
		Std Solution
		 int k;
		 for (k=1;k<=n;k++){
		 //# if (n%k==0&&table[rank[k]]==n-k){
		 	//# break;
		 //# }
		 }
		 printf("%d\n",n/k);
	 */

		/*My Solution*/
		int ans = n;
		for (i=1;i<n;i++){
			//# cout << "rank[i] " << rank[i] << endl;
			if (table[rank[i]] == n - sa[rank[i]] && n % (n-table[rank[i]]) == 0)	
				ans = min(ans,n-table[rank[i]]);
		}
		printf("%d\n",n/ans);

	}
	return 0;
}







發佈了150 篇原創文章 · 獲贊 30 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章