1. 程式人生 > >2016vijos 1-1 兔子的字串(字尾陣列 + 二分 + 雜湊)

2016vijos 1-1 兔子的字串(字尾陣列 + 二分 + 雜湊)

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

#define N 100001

typedef long long LL;

const int base=13331;

int n,m;
char s[N];

int a[N];
int v[N];
int p,q=1,k;
int sa[2][N],rk[2][N];
int h[N];

unsigned long long Pow[N],has[N];

pair
<int,int>interval[N]; void mul(int *sa,int*rk,int *SA,int *RK) { for(int i=1;i<=n;++i) v[rk[sa[i]]]=i; for(int i=n;i;--i) if(sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k; for(int i=n-k+1;i<=n;++i) SA[v[rk[i]]--]=i; for(int i=1;i<=n;++i) RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1
]] || rk[SA[i]+k]!=rk[SA[i-1]+k]); } void presa() { for(int i=1;i<=n;++i) v[a[i]]++; for(int i=1;i<=26;++i) v[i]+=v[i-1]; for(int i=1;i<=n;++i) sa[p][v[a[i]]--]=i; for(int i=1;i<=n;++i) rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]); for(k=1;k<n;k<<=1
,swap(p,q)) mul(sa[p],rk[p],sa[q],rk[q]); } void get_height() { int j,k=0; for(int i=1;i<=n;++i) { j=sa[p][rk[p][i]-1]; while(a[i+k]==a[j+k]) k++; h[rk[p][i]]=k; if(k) k--; } } void prehash() { Pow[0]=1; for(int i=1;i<=n;++i) Pow[i]=Pow[i-1]*base; for(int i=1;i<=n;++i) has[i]=has[i-1]*base+a[i]; } pair<int,int>select(LL k) { int now; LL sum=0; int l,r; for(int i=1;i<=n;++i) { now=interval[i].second-interval[i].first+1; if(sum+now>=k) { l=sa[p][i]; r=interval[i].first+k-sum-1; return make_pair(l,r); } sum+=now; } } unsigned long long get_hash(int l,int r) { return has[r]-has[l-1]*Pow[r-l+1]; } int cmp(pair<int,int>x,pair<int,int>y) { if(get_hash(x.first,x.second)==get_hash(y.first,y.second)) return 0; int Lx=x.second-x.first+1,Ly=y.second-y.first+1; int l=1,r=min(Lx,Ly),mid,tmp=0; while(l<=r) { mid=l+r>>1; if(get_hash(x.first,x.first+mid-1)==get_hash(y.first,y.first+mid-1)) tmp=mid,l=mid+1; else r=mid-1; } if(tmp<min(Lx,Ly)) return s[x.first+tmp]<s[y.first+tmp] ? -1 : 1; return Lx<Ly ? -1 : 1; } bool check(pair<int,int>now) { int l=n,r=n,sum=1; while(l>=1) if(cmp(make_pair(l,r),now)==1) { if(l==r) return false; r=l; sum++; if(sum>m) return false; } else l--; return true; } void solve() { LL l=1,r=0; for(int i=1;i<=n;++i) { interval[i].first=sa[p][i]+h[i]; interval[i].second=n; r+=interval[i].second-interval[i].first+1; } LL mid,tmp; pair<int,int>now; while(l<=r) { mid=l+r>>1; now=select(mid); if(check(now)) tmp=mid,r=mid-1; else l=mid+1; } now=select(tmp); l=now.first; r=now.second; for(int i=l;i<=r;++i) putchar(s[i]); } int main() { freopen("string.in","r",stdin); freopen("string.out","w",stdout); scanf("%d",&m); scanf("%s",s+1); n=strlen(s+1); for(int i=1;i<=n;++i) a[i]=s[i]-'a'+1; presa(); get_height(); prehash(); solve(); }

相關推薦

2016vijos 1-1 兔子字串字尾陣列 + 二分 +

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 100001 typedef long long LL; const

POJ 2774 字尾陣列 || 二分+

Long Long Message Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 35607  

2018.11.30 spoj220 Relevant Phrases of Annihilation字尾陣列+二分答案

傳送門 程式碼: 先用特殊字元把所有字串連線在一起。 然後二分答案將 s a sa

【BZOJ4698】[SDOI2008] Sandy的卡片字尾陣列+二分

點此看題面 大致題意: 給你\(N\)個序列,若定義兩個相同子串為一個子串內所有數加上一個數後能變成另一個串,求所有序列中的最長相同子串的長度。 簡單的轉化 首先,我們對題目進行一個簡單的轉化。 要求子串內所有數加上一個數後能變成另一個串,實際上就是要求這兩個子串中相鄰元素之差相等。 因此,我們

18.12.10 POJ 3450 Corporate Identity字尾陣列+二分

描述 Beside other services, ACM helps companies to clearly state their “corporate identity”, which includes company logo but also other signs, like trademar

洛谷4248 AHOI2013差異 字尾陣列SA+單調棧

題目連結 補部落格! 首先我們觀察題目中給的那個求\(ans\)的方法,其實前兩項沒什麼用處,直接\(for\)一遍就求得了 for (int i=1;i<=n;i++) ans=ans+i*(n-1); 那麼我們考慮剩下的部分應該怎麼求解! 首先這裡有一個性質。對於任意兩個字尾\(i,j\),他們的

2406 Power Strings 字尾陣列dc3演算法模板

題目:給出一個字串 問它最多由多少相同的字串組成 。 kmp簡單的三十行程式碼而且時間還快,一切都是為了dc3模板 /* 複雜度接近O(n) 所有相關陣列都要開三倍 */ #include<iostream> #include<cstdio> #i

字串進位制

雜湊的過程,其實可以看作對一個串的單向加密過程,並且需要保證所加的密不能高概率重複(就像不能讓隔壁老王輕易地用它家的鑰匙開啟你家門一樣qwq),通過這種方式來替代一些很費時間的操作。 比如,最常見的,當然就是通過雜湊陣列來判斷幾個串是否相同(洛谷p3370)。此處的操作呢,

perl切片陣列

切片用法可在陣列和雜湊中提取值 陣列中取陣列 my @array = qw(aa bb cc dd); my @select = @array[1,3]; print "@select\n"

【POJ - 3320 】Jessica's Reading Problem 尺取,

題幹: Jessica's a very lovely girl wooed by lots of boys. Recently she has a problem. The final exam is coming, yet she has spent little time on it.

洛谷2408不同字串個數/SPOJ 694/705 字尾陣列SA

真是一個三倍經驗好題啊。 我們來觀察這個題目,首先如果直接整體計算,怕是不太好計算。 首先,我們可以將每個子串都看成一個字尾的的字首。那我們就可以考慮一個一個字尾來計算了。 為了方便起見,我們選擇按照字典序來一次插入每個字尾,然後每次考慮當前字尾會產生的新串和與之前插入的串重複的串(這裡之所以可以這麼考

poj2774字尾陣列||字串hash

求兩個串的最長公共子串 將兩個串連起來,求字尾陣列,sa中相鄰兩個字尾如果不屬於同一個模版,則用這個height更新答案,他們的最長公共字首更新答案 #include<cstdio> #include<cstring> #include<cs

尋找一個字串中的最長重複子串字尾陣列&找出一個字串中最長不重複子串

一、尋找一個字串中的最長重複子串(字尾陣列) 字尾陣列其實可以看尋找一個字串中的最長重複子串(字尾陣列)作一個由字串s倒數i個字元組成的子串的集合,其中0<i<s.length(),例如 字串strstr的字尾陣列為: {r,tr,str,rstr,trstr,

SPOJ-694-求字串中不同子串個數字尾陣列

http://www.spoj.com/status/ns=17418952 【每一個子串必然是某個字尾的字首】,因此我們統計出所有的字尾中有多少個不同的字首,就是所有不重複子串的數量了 而這個相同的字首個數,當然就是所有height之和啦。 所以答案就是n*(n-1)/

字串匹配字尾陣列

假設已經求出字串S的字尾陣列點選開啟連結,現在要求字串T在字串S中出現的位置,只要通過二分搜尋就可以在O(T*logS)時間內完成。當S比較大時,比O(T+S)的演算法更為高效,所以需要對同樣的字串做

第十五章 加密算法實例1--註冊登錄消息摘要算法

其他 open targe 代碼 type .get stack static app 15.1、原理步驟 註冊:註冊時,將用戶密碼加密放入數據庫 登錄:登錄時,將用戶密碼采用上述相同的算法加密,之後再與數據庫中的信息進行比對,若相同,則登錄 15.2、實現(這裏采用了

第一章 概論 計算機網絡筆記 學堂在線 1.3交換方式電路交換、分組交換

機制 雙向 鏈路 導致 控制 嚴格 計算 電話 節點數 交換就是要建立兩種機制:   建立數據傳輸通路機制   控制數據傳輸過程機制 信道:是信號傳輸通道   1 發送端將數據轉換成信號   2 信號經過信道傳播到達接收端   3 接收端將信號還原成數據 1 電路交換

BZOJ3238: [Ahoi2013]差異字尾陣列

Description Input 一行,一個字串S Output 一行,一個整數,表示所求值 Sample Input cacao Sample Output 54 解題思路: 看到lcp,想到了height陣列,沒錯,這道題是一道字尾陣列

2018.11.24 poj3261Milk Patterns字尾陣列

傳送門 字尾陣列經典題。 貌似可以用二分答案+字尾陣列? 我自己 y y yy

2018.11.24 poj3693Maximum repetition substring字尾陣列

傳送門 字尾陣列好題。 考慮列舉迴圈節長度 l e n