【bzoj2081】[Poi2010]Beads Hash
題目描述
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