1. 程式人生 > >【HackerRank】Functional Palindromes(迴文樹+字尾陣列+lcp排序+字串雜湊+二分)

【HackerRank】Functional Palindromes(迴文樹+字尾陣列+lcp排序+字串雜湊+二分)

這個頁面抓不太好,大家點進去看吧~~

做過的用到資料結構+演算法最多的一個題……真真是做ACM以來做的最最麻煩的一個題……

說白了其實就是板子大雜燴……但是會吐的那種。。

此外……此題價值75$……不要問我為什麼。。。TOT

現在進入正片——

給你一個長n的字串,僅由小寫字母組成。然後q次詢問。
每次詢問該串的所有迴文子串裡,按字典序從小到大後第k個的迴文串。輸出它的f函式值。注意迴文串不去重。

具體要做的就是,預處理母串的所有迴文串,按字典序排序,然後快速找到第k個,輸出對應f值。

分為如下子問題:
1·預處理母串所有迴文子串——迴文樹,具體百度,然後與迴文樹惡戰一場吧……!¥@#¥。然後可以把本質不同的迴文子串以及對應的出現次數存起來,然後排序。存迴文子串可以存該種迴文子串出現的左右下標——用以排序。

2·把迴文子串按字典序排序——預處理母串的字尾陣列,然後可以搞RMQ,弄出來個快速lcp。這樣對於上一步存起來的本質不同的迴文子串左右下標,通過比較lcp,可以達到快速按字典序排序。

3·快速找到第k個——二分,預處理到某個串所需要的k的下界,這樣可以快速二分出第k個串。

4·f函式——字串雜湊,一套板子生砸上……

然後就出來了……GG。。。

因為是邊學邊造輪子,所以程式碼比較醜陋……
程式碼如下:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector> #include <queue> #include <algorithm> #define LL long long #define Pr pair<int,int> using namespace std; const int INF = 0x3f3f3f3f; const int mod = 1e9+7; const int MAXN = 112345; int t1[MAXN],t2[MAXN],c[MAXN]; bool cp(int *r,int a,int b,int l) { return
r[a] == r[b] && r[a+l] == r[b+l]; } void da(char *str,int *sa,int *rk,int *height,int n,int m) { n++; int i,j,p,*x = t1,*y = t2; for(i = 0; i < m; ++i) c[i] = 0; for(i = 0; i < n; ++i) c[x[i] = str[i]]++; for(i = 1; i < m; ++i) c[i] += c[i-1]; for(i = n-1; i >= 0; --i) sa[--c[x[i]]] = i; for(j = 1; j <= n; j <<= 1) { p = 0; for(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 < m; ++i) c[i] = 0; for(i = 0; i < n; ++i) c[x[y[i]]]++; for(i = 1; i < m; ++i) c[i] += c[i-1]; for(i = n-1; i >= 0; --i) sa[--c[x[y[i]]]] = y[i]; swap(x,y); p = 1; x[sa[0]] = 0; for(i = 1; i < n; ++i) x[sa[i]] = cp(y,sa[i-1],sa[i],j)? p-1: p++; if(p >= n) break; m = p; } int k = 0; n--; for(i = 0; i <= n; ++i) rk[sa[i]] = i; for(i = 0; i < n; ++i) { if(k) k--; j = sa[rk[i]-1]; while(str[i+k] == str[j+k]) k++; height[rk[i]] = k; } } int rk[MAXN],height[MAXN]; int RMQ[MAXN]; int mm[MAXN]; int best[20][MAXN]; void initRMQ(int n) { mm[0] = -1; for(int i = 1; i <= n; ++i) mm[i] = ((i&(i-1)) == 0)? mm[i-1]+1: mm[i-1]; for(int i = 1; i <= n; ++i) best[0][i] = i; for(int i = 1; i <= mm[n]; i++) for(int j = 1; j +(1<<i)-1 <= n; j++) { int a = best[i-1][j]; int b = best[i-1][j+(1<<(i-1))]; if(RMQ[a] < RMQ[b]) best[i][j] = a; else best[i][j] = b; } } int askRMQ(int a,int b) { int t; t = mm[b-a+1]; b -= (1<<t)-1; a = best[t][a]; b = best[t][b]; return RMQ[a] < RMQ[b]? a: b; } int lcp(int a,int b,int len) { if(a == b) return len-a; a = rk[a]; b = rk[b]; if(a > b) swap(a,b); return height[askRMQ(a+1,b)]; } struct node { int next[26]; int len; int sufflink; int num,l,r; }; char s[112345]; node tree[MAXN]; int num; // node 1 - root with len -1, node 2 - root with len 0 int suff; // max suffix palindrome bool addLetter(int pos) { int cur = suff, curlen = 0; int let = s[pos] - 'a'; while (true) { curlen = tree[cur].len; if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos]) break; cur = tree[cur].sufflink; } if (tree[cur].next[let]) { suff = tree[cur].next[let]; tree[suff].num++; return false; } num++; suff = num; tree[num].len = tree[cur].len + 2; tree[num].r = pos; tree[num].l = pos-tree[num].len+1; tree[cur].next[let] = num; if (tree[num].len == 1) { tree[num].sufflink = 2; tree[num].num = 1; return true; } tree[num].num++; while (true) { cur = tree[cur].sufflink; curlen = tree[cur].len; if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos]) { tree[num].sufflink = tree[cur].next[let]; break; } } return true; } void initTree() { num = 2; suff = 2; tree[1].len = -1; tree[1].sufflink = 1; tree[2].len = 0; tree[2].sufflink = 1; } int len; int r[MAXN]; int sa[MAXN]; vector <int> adj[MAXN]; vector <pair<Pr,int> > vc; void dfs(int u) { for(int i = 0; i < adj[u].size(); ++i) { dfs(adj[u][i]); tree[u].num += tree[adj[u][i]].num; } } bool cmp(pair<Pr,int> a,pair<Pr,int> b) { int l1,l2,r1,r2,len1,len2; l1 = a.first.first; l2 = b.first.first; r1 = a.first.second; r2 = b.first.second; len1 = r1-l1+1; len2 = r2-l2+1; int cp = lcp(l1,l2,len); if(cp >= len1 || cp >= len2) return len1 <= len2; else return s[l1+cp] <= s[l2+cp]; } int P[MAXN],HashF[MAXN],HashR[MAXN]; class RollingHash { public: RollingHash() { prime = 100001; mod1 = 1000000007; mod2 = 1897266401; P[0] = 1; for(int i=1; i<MAXN; i++) { P[i] = 1LL * P[i-1] * prime % mod1; } } void Construct() { HashF[0] = HashR[ len+1 ] = 0; for(int i=1; i<=len; i++) { HashF[i] = ( 1LL * HashF[i-1] * prime + s[i-1] ) % mod1; HashR[len-i+1] = ( 1LL * HashR[len-i+2] * prime + s[ len - i ] ) % mod1; } } int GetForwardHash( int l, int r ) { if( l == 1 ) return HashF[r]; int hash = HashF[r] - 1LL * HashF[l-1] * P[ r - l + 1 ] % mod1; if( hash < 0 ) hash += mod1; return hash; } int GetBackwardHash( int l, int r ) { if( r == len ) return HashR[l]; int hash = HashR[l] - 1LL * HashR[r+1] * P[ r - l + 1 ] % mod1; if( hash < 0 ) hash += mod1; return hash; } bool IsPalin( int l, int r ) { if( r < l ) return true; return (GetForwardHash(l, r) == GetBackwardHash(l, r)); } private: int prime, mod1, mod2; }; vector <pair<LL,int> > by; LL ans[MAXN]; LL cnt; void init() { da(s,sa,rk,height,len,128); for(int i = 1; i <= len; ++i) RMQ[i] = height[i]; initRMQ(len); initTree(); for (int i = 0; i < len; i++) addLetter(i); for(int i = 2; i <= num; ++i) adj[tree[i].sufflink].push_back(i); dfs(1); for(int i = 3; i <= num; ++i) vc.push_back(pair<Pr,int> (Pr(tree[i].l,tree[i].r),tree[i].num)); sort(vc.begin(),vc.end(),cmp); RollingHash obj; obj.Construct(); cnt = 1; for(int i = 0; i < vc.size(); ++i) { by.push_back(pair<LL,int> (cnt,i)); ans[i] = obj.GetForwardHash(vc[i].first.first+1,vc[i].first.second+1); //printf("%d %d %lld\n",vc[i].first.first+1,vc[i].first.second+1,ans[i]); cnt += vc[i].second; } } int main() { int q; LL k; scanf("%d%d",&len,&q); scanf("%s",s); init(); int pos; while(q--) { scanf("%lld",&k); if(k >= cnt) puts("-1"); else { pos = -1; int l = 0,r = by.size()-1; while(l <= r) { int mid = (l+r)>>1; if(k >= by[mid].first) { pos = mid; l = mid+1; } else r = mid-1; } printf("%lld\n",ans[by[pos].second]); } } return 0; }

相關推薦

HackerRankFunctional Palindromes+字尾陣列+lcp排序+字串+二分

這個頁面抓不太好,大家點進去看吧~~ 做過的用到資料結構+演算法最多的一個題……真真是做ACM以來做的最最麻煩的一個題…… 說白了其實就是板子大雜燴……但是會吐的那種。。 此外……此題價值75$……不要問我為什麼。。。TOT 現在進入正片—— 給你

清華集訓2017模擬12.10+鏈剖分

Description: NYG 很喜歡研究迴文串問題,有一天他想到了這樣一個問題: 給出一個字串 S,現在有 4 種操作: • addl c :在當前字串的左端加入字元 c; • addr c :在當前字串的右端加入字元 c; • transl l

LeetCode516. 最長子序列

題目連結:https://leetcode-cn.com/problems/longest-palindromic-subsequence/description/ 題目描述 給定一個字串s,找到其中最長的迴文子序列。可以假設s的最大長度為1000。 示例 輸入: “

LeetCode 409. 最長

1.題目 給定一個包含大寫字母和小寫字母的字串,找到通過這些字母構造成的最長的迴文串。 在構造過程中,請注意區分大小寫。比如 “Aa” 不能當做一個迴文字串。 注意: 假設字串的長度不會超過 1010。 2.思路 建立map存放26個大小寫字母的數量; 如果該字

bzoj2342[Shoi2011]雙倍

題目連結 發現部落格裡沒有迴文樹的板子 所以寫一道**題來補一下(話說我之前都沒補嗎 被學長嘲諷部落格裡都是模板(我的部落格就是用來存模板的ya hahahahahhaa 這題就是瞎搞 不用想太多直接瞎搞 迴文樹建出來 問題就轉化成對於 每個長度為4的倍數、且fa

LeetCode214. 最短串 結題報告 (C++)

原題地址:https://leetcode-cn.com/problems/shortest-palindrome/ 題目描述: 給定一個字串 s,你可以通過在字串前面新增字元將其轉換為迴文串。找到並返回可以用這種方式轉換的最短迴文串。 示例 1: 輸入: "aacecaaa" 輸出

LeetCode#5最長子串(Longest Palindromic Substring)

【LeetCode】#5最長迴文子串(Longest Palindromic Substring) 題目描述 給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為 1000。 示例 示例 1: 輸入: “babad” 輸出: “bab” 注意: “a

leetcode5. 最長子串

我們就可以在 O(n^2)O(n2) 的時間內解決這個問題。 我們觀察到迴文中心的兩側互為映象。因此,迴文可以從它的中心展開,並且只有 (2n - 1 )個這樣的中心。 你可能會問,為什麼會是 2n

題解洛谷P1435 子串(區間dp)

IOI 2000的題目 實際上是一道區間dp 我們設dp[i][j]代表字串中第i個字元到第j個字元得到迴文串需要新增的字元數,初始化dp[i][i]為0。這裡注意還應該初始化dp[i][i+1],如果s[i]==s[i+1]那麼dp[i][i+1]=0,否則=1。接著我們

PAT進位制

題目描述 如果一個數字從左邊讀和從右邊讀一樣,那麼這個數字就是一個迴文數。例如32123就是一個迴文數;17在某種意義上也是一個迴文數,因為它的二進位制型式——10001——是一個迴文數。 請你幫忙

LeetCode5# 最長子串

題目描述 給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為 1000。 示例 1: 輸入: "babad" 輸出: "bab" 注意: "aba" 也是一個有效答案。 示例 2: 輸入: "cbbd" 輸出: "bb" 思路 本題運用了一些動態規劃的思想,關於動態規

LeetCode5. 最長子串 結題報告 (C++)

題目描述:給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為1000。示例 1:輸入: "babad" 輸出: "bab" 注意: "aba"也是一個有效答案。 示例 2:輸入: "cbbd" 輸出: "bb" 解題方法:不會做,從網上扒的程式碼。學習

專題計數問題排列組合,容斥原理,卡特蘭數

spl 狀態 ans 補集 方便 常用 括號 inf 不存在 ---下面都是學習的筆記,還沒有整理,比較淩亂,有需自取吧。--- 【排列組合】 <加法原理>做一件事情有n個方法,第i個方法有pi種方案,則一共有p1+p2+...+pn種方案。 <乘法原理&

Hdu4825Xor Sum01字典

insert else 結果 char clu 向人 logs mark 每次 Description Zeus 和 Prometheus 做了一個遊戲,Prometheus 給 Zeus 一個集合,集合中包含了N個正整數,隨後 Prometheus 將向 Zeus 發起M

BZOJ5329SDOI2018戰略遊戲圓方,虛

FN 貢獻 地圖 return http top char Go show 【BZOJ5329】【SDOI2018】戰略遊戲(圓方樹,虛樹) 題面 BZOJ 洛谷 Description 省選臨近,放飛自我的小Q無心刷題,於是慫恿小C和他一起頹廢,玩起了一款戰略遊戲。 這款

CF245H Queries for Number of Palindromes

iostream als 思路 離線 void ngs single pri des 題意翻譯 題目描述 給你一個字符串s由小寫字母組成,有q組詢問,每組詢問給你兩個數,l和r,問在字符串區間l到r的字串中,包含多少回文串。 輸入格式 第1行,給出s,s的長度小於5000

BZOJ2809[APIO2012] dispatching左偏例題

點此看題面 大致題意: 有\(N\)名忍者,每名忍者有三個屬性:上司\(B_i\),薪水\(C_i\)和領導力\(L_i\)。你要選擇一個忍者作為管理者,然後在所有被他管理的忍者中選擇若干名忍者,使薪水總和不超過預算\(M\)。現讓你最大化被派遣的忍者總數乘以管理者的領導力水平。 關於左偏樹 這道題

BZOJ4044: [Cerc2014] Virus synthesis+DP

Description Viruses are usually bad for your health. How about fighting them with... other viruses? In  this problem, you need to find o

計蒜客 2018南京網路賽 I Skr

題目:給一串由0..9組成的數字字串,求所有不同迴文串的權值和。比如說“1121”這個串中有“1”,“2”,“11”,“121”三種迴文串,他們的權值分別是1,2,11,121。最終輸出ans=135。 思路:之前寫了馬拉車的演算法,網上看到的這個題是迴文樹的模板題。。。

17E E. Palisection

In an English class Nick had nothing to do at all, and remembered about wonderful strings called palindromes. We should remind you