1. 程式人生 > >【bzoj2081】[Poi2010]Beads Hash

【bzoj2081】[Poi2010]Beads Hash

true 最終 便宜 可能 一個 clear 串珠子 中間 進行

題目描述

Zxl有一次決定制造一條項鏈,她以非常便宜的價格買了一長條鮮艷的珊瑚珠子,她現在也有一個機器,能把這條珠子切成很多塊(子串),每塊有k(k>0)個珠子,如果這條珠子的長度不是k的倍數,最後一塊小於k的就不要拉(nc真浪費),保證珠子的長度為正整數。 Zxl喜歡多樣的項鏈,為她應該怎樣選擇數字k來盡可能得到更多的不同的子串感到好奇,子串都是可以反轉的,換句話說,子串(1,2,3)和(3,2,1)是一樣的。寫一個程序,為Zxl決定最適合的k從而獲得最多不同的子串。 例如:這一串珠子是: (1,1,1,2,2,2,3,3,3,1,2,3,3,1,2,2,1,3,3,2,1), k=1的時候,我們得到3個不同的子串: (1),(2),(3) k=2的時候,我們得到6個不同的子串: (1,1),(1,2),(2,2),(3,3),(3,1),(2,3) k=3的時候,我們得到5個不同的子串: (1,1,1),(2,2,2),(3,3,3),(1,2,3),(3,1,2) k=4的時候,我們得到5個不同的子串: (1,1,1,2),(2,2,3,3),(3,1,2,3),(3,1,2,2),(1,3,3,2)

輸入

共有兩行,第一行一個整數n代表珠子的長度,(n<=200000),第二行是由空格分開的顏色ai(1<=ai<=n)。

輸出

也有兩行,第一行兩個整數,第一個整數代表能獲得的最大不同的子串個數,第二個整數代表能獲得最大值的k的個數,第二行輸出所有的k(中間有空格)。

樣例輸入

21
1 1 1 2 2 2 3 3 3 1 2 3 3 1 2 2 1 3 3 2 1

樣例輸出

6 1


題解

Hash

處理不同字符串問題,Hash是個好方法。

然而這道題要求反過來的字符串與原串算作同一種,所以Hash值也應相同。

一種比較簡單且容易實現的方法是把它們正反做兩次Hash,然後把它們乘起來作為新的Hash值,因為乘法滿足交換率。

這裏為了防止被卡取了兩個底數進行Hash。

最終使用map判斷就行了。

時間復雜度為$O(n\log n*\log n)=O(n\log^2n)$

#include <cstdio>
#include <map>
#define N 200010
using namespace std;
typedef unsigned long long ull;
struct data
{
	ull b[N] , h1[N] , h2[N];
	ull hash(int l , int r)
	{
		return (h1[r] - h1[l - 1] * b[r - l + 1]) * (h2[l] - h2[r + 1] * b[r - l + 1]);
	}
}t1 , t2;
map<pair<ull , ull> , bool> f;
int a[N] , sta[N] , top;
int main()
{
	int n , i , j , cnt , ans = 0;
	scanf("%d" , &n);
	t1.b[0] = t2.b[0] = 1;
	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]);
	for(i = 1 ; i <= n ; i ++ ) t1.b[i] = t1.b[i - 1] * 233 , t2.b[i] = t2.b[i - 1] * 2333;
	for(i = 1 ; i <= n ; i ++ ) t1.h1[i] = t1.h1[i - 1] * 233 + a[i] , t2.h1[i] = t2.h1[i - 1] * 2333 + a[i];
	for(i = n ; i >= 1 ; i -- ) t1.h2[i] = t1.h2[i + 1] * 233 + a[i] , t2.h2[i] = t2.h2[i + 1] * 2333 + a[i];
	for(i = 1 ; i <= n ; i ++ )
	{
		f.clear() , cnt = 0;
		for(j = 1 ; j + i - 1 <= n ; j += i)
			if(!f[make_pair(t1.hash(j , j + i - 1) , t2.hash(j , j + i - 1))])
				f[make_pair(t1.hash(j , j + i - 1) , t2.hash(j , j + i - 1))] = 1 , cnt ++ ;
		if(cnt > ans) top = 1 , sta[top] = i , ans = cnt;
		else if(cnt == ans) sta[++top] = i;
	}
	printf("%d %d\n" , ans , top);
	for(i = 1 ; i < top ; i ++ ) printf("%d " , sta[i]);
	printf("%d" , sta[top]);
	return 0;
}

【bzoj2081】[Poi2010]Beads Hash