具體請看論文....php
不重疊的最長重複子串node
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; #define N 20100 int p[N]; int sa[N],rank[N],height[N]; int wa[N],wb[N],c[N]; //sa[i] 表示排名爲i的下標 //rank[i]表示i的排名 //height[i]表示sa[i]和sa[i-1]的最長前綴 void build_sa(int s[],int n,int m) { int i,j,p,*x = wa,*y = wb; //初始化基數排序 for(i = 0;i < m;i ++) c[i] = 0; for(i = 0;i < n;i ++) c[x[i] = s[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; //y[i] 表示第二關鍵字排名爲i的下標 for(i = n-j;i < n;i ++) y[p++] = i; //若是後綴長度不到j的,第二關鍵字排名靠前 for(i = 0;i < n;i ++) if(sa[i] >= j) y[p++] = sa[i] - j; //sa[i] < j的時候不可能爲第二關鍵字,位置sa[i]-j的第二關鍵字爲sa[i], //他的排名爲p //按第一關鍵字排序 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]; //按y數組的存的下標順序,基數排序 for(i = n-1;i >= 0;i --) sa[--c[x[y[i]]]] = y[i]; swap(x,y); //生成新的x數組,交換成y,是爲了節省空間.... p = 1;x[sa[0]] = 0; //若是兩個關鍵字都同樣,下次的第一關鍵字同樣。 for(i = 1;i < n;i ++) x[sa[i]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++; if(p >= n) break; m = p; } } void get_height(int s[],int n) { int i,j,k = 0; for(i = 1;i <= n;i ++) rank[sa[i]] = i; //看論文,有證實 for(i = 0;i < n;i ++) { if(k) k--; j = sa[rank[i]-1]; while(s[i+k]==s[j+k]) k ++; height[rank[i]] = k; } } int judge(int mid,int n) { int minz,maxz,i; minz = maxz = sa[1]; for(i = 2;i <= n;i ++) { if(height[i] < mid) { minz = maxz = sa[i]; } else { maxz = max(maxz,sa[i]); minz = min(minz,sa[i]); if(maxz-minz > mid) return 1; } } return 0; } int main() { int n,i; while(scanf("%d",&n)!=EOF) { if(n == 0) break; for(i = 0;i < n;i ++) scanf("%d",&p[i]); for(i = 0;i < n-1;i ++) p[i] = p[i+1] - p[i] + 90; n --; p[n] = 0; build_sa(p,n+1,200); get_height(p,n); int str,mid,end; str = 1; end = n/2; while(str < end) { mid = (str+end + 1)/2; if(judge(mid,n)) str = mid; else end = mid-1; } if(end >= 4) printf("%d\n",end+1); else printf("0\n"); } return 0; }
數據很是水,本意是可重疊k次最長子串。數組
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; #define N 20100 int p[N]; int sa[N],rank[N],height[N]; int wa[N],wb[N],c[N]; void build_sa(int s[],int n,int m) { int i,j,p,*x = wa,*y = wb; for(i = 0;i < m;i ++) c[i] = 0; for(i = 0;i < n;i ++) c[x[i] = s[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]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++; if(p >= n) break; m = p; } } void get_height(int s[],int n) { int i,j,k = 0; for(i = 1;i <= n;i ++) rank[sa[i]] = i; for(i = 0;i < n;i ++) { if(k) k--; j = sa[rank[i]-1]; while(s[i+k]==s[j+k]) k ++; height[rank[i]] = k; } } int judge(int mid,int n,int k) { int flag,i; flag = 1; for(i = 2;i <= n;i ++) { if(height[i] < mid) { if(flag >= k) return 1; flag = 1; } else { flag ++; } } if(flag >= k) return 1; else return 0; } int main() { int n,i,maxz,k; while(scanf("%d%d",&n,&k)!=EOF) { maxz = 0; for(i = 0;i < n;i ++) { scanf("%d",&p[i]); p[i] ++; maxz = max(maxz,p[i]); } p[n] = 0; build_sa(p,n+1,maxz+20); get_height(p,n); int str,mid,end; str = 1; end = n/2; while(str < end) { mid = (str+end + 1)/2; if(judge(mid,n,k)) str = mid; else end = mid-1; } printf("%d\n",end); } return 0; }
注意把C數組開到N....傻了...ui
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; #define N 200100 int sa[N],rank[N],height[N]; int c[N],wa[N],wb[N]; char s1[N],s2[N]; int p[N]; void build_sa(int s[],int n,int m) { int i,j,p,*x = wa,*y = wb; for(i = 0;i < m;i ++) c[i] = 0; for(i = 0;i < n;i ++) c[x[i] = s[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]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++; if(p >= n) break; m = p; } } void get_height(int s[],int n) { int i,j,k = 0; for(i = 1;i <= n;i ++) rank[sa[i]] = i; for(i = 0;i < n;i ++) { if(k) k --; j = sa[rank[i]-1]; while(s[i+k] == s[j+k]) k ++; height[rank[i]] = k; } } int main() { int i,len1,len2,j,n; scanf("%s%s",s1,s2); len1 = strlen(s1); j = 0; for(i = 0;i < len1;i ++) p[j++] = s1[i]-'a'+1; p[j++] = 28; len2 = strlen(s2); for(i = 0;i < len2;i ++) p[j++] = s2[i]-'a'+1; p[j] = 0; n = j; build_sa(p,n+1,30); get_height(p,n); int ans = 0; for(i = 1;i <= n;i ++) { if(sa[i] < len1&&sa[i-1] > len1) ans = max(ans,height[i]); if(sa[i] > len1&&sa[i-1] < len1) ans = max(ans,height[i]); } printf("%d\n",ans); return 0; }
感受複雜度挺高的,n=1的時候須要特判。寫的代碼有些亂....3d
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; #define N 200100 int sa[N],height[N],rank[N]; int c[N],wa[N],wb[N]; int p[N]; char str[101][1101]; int flag[N]; int o[101]; int t; void build_sa(int s[],int n,int m) { int i,j,p,*x = wa,*y = wb; for(i = 0; i < m; i ++) c[i] = 0; for(i = 0; i < n; i ++) c[x[i] = s[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]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++; if(p >= n) break; m = p; } } void get_height(int s[],int n) { int i,j,k = 0; for(i = 1; i <= n; i ++) rank[sa[i]] = i; for(i = 0; i < n; i ++) { if(k) k --; j = sa[rank[i]-1]; while(s[i+k] == s[j+k]) k ++; height[rank[i]] = k; } } int judge(int mid,int n) { int i,j; memset(o,0,sizeof(o)); o[flag[sa[1]]] = 1; for(i = 2; i <= n; i ++) { if(height[i] < mid) { int temp = 0; for(j = 1; j <= t; j ++) { if(o[j]) temp ++; o[j] = 0; } if(temp > t/2) return 1; o[flag[sa[i]]] = 1; } else { o[flag[sa[i]]] = 1; } } int temp = 0; for(j = 1; j <= t; j ++) { if(o[j]) temp ++; o[j] = 0; } if(temp > t/2) return 1; return 0; } void fun(int key,int end) { int temp = 0,i; for(i = 1; i <= t; i ++) { if(o[i]) temp ++; o[i] = 0; } if(temp > t/2) { for(i = 0; i < end; i ++) { printf("%c",p[sa[key]+i]-1+'a'); } printf("\n"); } } int main() { int n,i,j,len,num,temp,f; f = 0; while(scanf("%d",&n)!=EOF) { t = n; if(f)printf("\n"); f = 1; if(n == 0) break; num = 0; temp = 30; for(i = 0; i < n; i ++) { scanf("%s",str[i]); len = strlen(str[i]); for(j = 0; j < len; j ++) { flag[num] = i+1; p[num++] = str[i][j]-'a'+1; } flag[num] = 0; if(i != n-1) p[num++] = temp++; else p[num] = 0; } if(n == 1) { printf("%s\n",str[0]); continue; } build_sa(p,num+1,temp+10); get_height(p,num); int str,end,mid; str = 0; end = 5000; //for(i = 1;i <= num;i ++) //printf("%d ",height[i]); while(str < end) { mid = (str + end + 1)/2; if(judge(mid,num)) str = mid; else end = mid - 1; } if(end == 0) { printf("?\n"); continue; } int sz[101]; memset(sz,0,sizeof(sz)); memset(o,0,sizeof(o)); o[flag[sa[1]]] = 1; for(i = 2; i <= num; i ++) { if(height[i] < end) { fun(i-1,end); o[flag[sa[i]]] = 1; } else { o[flag[sa[i]]] = 1; } } fun(num,end); } return 0; }
最長迴文串,跑的有些慢...
這份代碼 是水過的,我找的是相鄰的最大值而且兩個後綴必須在前面或後面,可是abcdba會把abba當成回聞....這題若是改爲rmq的話,目測會MLE+TLE,放棄治療了。
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cmath> using namespace std; #define N 2010000 char str[1000001]; int sa[N],height[N],rank[N]; int p[N],c[N],wa[N],wb[N]; void build_sa(int s[],int n,int m) { int i,j,p,*x = wa,*y = wb; for(i = 0;i < m;i ++) c[i] = 0; for(i = 0;i < n;i ++) c[x[i] = s[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]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++; if(p >= n) break; m = p; } } void get_height(int s[],int n) { int i,j,k = 0; for(i = 1;i <= n;i ++) rank[sa[i]] = i; for(i = 0;i < n;i ++) { j = sa[rank[i]-1]; if(k) k--; while(s[i+k] == s[j+k]) k ++; height[rank[i]] = k; } } int main() { int i,len,n,cas = 1; while(scanf("%s",str)!=EOF) { if(strcmp(str,"END") == 0) break; n = 0; len = strlen(str); for(i = 0;i < len;i ++) p[n++] = str[i]-'a'+1; p[n++] = 28; for(i = 0;i < len;i ++) p[n++] = str[len-i-1]-'a'+1; p[n] = 0; build_sa(p,n+1,30); get_height(p,n); int ans = 0; for(i = 1;i <= n;i ++) { if(sa[i-1] < len||sa[i] > len) ans = max(ans,height[i]); if(sa[i-1] > len||sa[i] < len) ans = max(ans,height[i]); } printf("Case %d: %d\n",cas++,ans); } return 0; }
最長迴文串,這是正解。rmq+後綴數組,調試了好一會,費勁啊!!
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cmath> using namespace std; #define N 2010000 int sa[N],height[N],Rank[N]; int c[N],p[N],wa[N],wb[N]; int bin[31]; int minz[22][N]; char str[N]; void build_sa(int s[],int n,int m) { int i,j,p,*x = wa,*y = wb; for(i = 0; i < m; i ++) c[i] = 0; for(i = 0; i < n; i ++) c[x[i] = s[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]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++; if(p >= n) break; m = p; } } void get_height(int s[],int n) { int i,j,k = 0; for(i = 1; i <= n; i ++) Rank[sa[i]] = i; for(i = 0; i < n; i ++) { if(k) k --; j = sa[Rank[i]-1]; while(s[i+k] == s[j+k]) k ++; height[Rank[i]] = k; } } void init(int n) { int i,j; for(i = 1; i <= n; i ++) minz[0][i] = height[i]; for(i = 1; bin[i] <= n; i ++) { for(j = 1; j + bin[i-1] <= n; j ++) { minz[i][j] = min(minz[i-1][j],minz[i-1][j+bin[i-1]]); } } } int rmq(int s,int t) { int k = log((t-s+1)*1.0)/log(2.0); return min(minz[k][s],minz[k][t-bin[k]+1]); } int main() { int i,len,n; scanf("%s",str); n = 0; len = strlen(str); for(i = 0; i < len; i ++) p[n++] = str[i]+1; p[n++] = 299; for(i = 0; i < len; i ++) p[n++] = str[len-i-1]+1; p[n] = 0; build_sa(p,n+1,300); get_height(p,n); for(i = 0; i < 21; i ++) bin[i] = 1<<i; init(n); int s,t,temp,pos,ans = 0; for(i = 0; i < len; i ++) { s = Rank[i+1]; t = Rank[2*len-i]; if(s > t) swap(s,t); s ++; temp = rmq(s,t)*2; if(ans < temp) { ans = temp; pos = i - temp/2 + 1; } s = Rank[i]; t = Rank[2*len-i]; if(s > t) swap(s,t); s ++; temp = rmq(s,t)*2 - 1; if(ans < temp) { ans = temp; pos = i - temp/2; } } for(i = 0;i < ans;i ++) printf("%c",str[pos+i]); return 0; }
POJ 3693 Maximum repetition substring
多是水過,看論文上的講解,徹底仍是不會啊....
枚舉那裏看懂了,尋找L*i和L*(i+1)往前最長和日後最長,不知道怎麼操做的。不會是把字符串倒過來而後再處理一遍吧。。。日後的很簡單,就是height最小值,往前就有點扯了,知道後面的長度x,若是前面的長度大於L- x%L那麼就會總長度會+1,總長度+2那些個狀況應該是不用考慮的,枚舉前面的時候已經算了。還有字典序,徹底是亂搞,看了一個大神寫的是吧L保存下來,而後枚舉sa,判斷是否可行.....作個題真難啊....
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cmath> using namespace std; #define N 100100 int bin[30]; int sa[N],height[N],rank[N]; int c[N],p[N],wa[N],wb[N]; char str[N]; int minz[22][N]; int que[10001]; void build_sa(int s[],int n,int m) { int i,j,p,*x = wa,*y = wb; for(i = 0;i < m;i ++) c[i] = 0; for(i = 0;i < n;i ++) c[x[i] = s[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]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++; if(p >= n) break; m = p; } } void get_height(int s[],int n) { int i,j,k = 0; for(i = 1;i <= n;i ++) rank[sa[i]] = i; for(i = 0;i < n;i ++) { if(k) k --; j = sa[rank[i]-1]; while(s[i+k] == s[j+k]) k ++; height[rank[i]] = k; } } void init(int n) { int i,j; for(i = 1;i <= n;i ++) minz[0][i] = height[i]; for(i = 1;bin[i] <= n;i ++) { for(j = 1;j +bin[i-1] <= n;j ++) { minz[i][j] = min(minz[i-1][j],minz[i-1][j+bin[i-1]]); } } } int rmq(int s,int t) { s = rank[s]; t = rank[t]; if(s > t) swap(s,t); s ++; int k = log((t-s+1)*1.0)/log(2.0); return min(minz[k][s],minz[k][t-bin[k]+1]); } int main() { int cas = 1,len,i,j; for(i = 0;i <= 20;i ++) bin[i] = 1<<i; while(scanf("%s",str)!=EOF) { if(str[0] == '#') break; len = strlen(str); for(i = 0;i < len;i ++) p[i] = str[i] - 'a'+1; p[len] = 0; build_sa(p,len+1,30); get_height(p,len); init(len); int ans = 0,num = 0; for(i = 1;i <= len;i ++) { for(j = 0;j < len;j += i) { if(j+i >= len) continue; int temp,lf,res; res = 0; temp = rmq(j,j+i); res = max(res,temp/i+1); lf = i - temp%i; if(j-lf >= 0) { temp = rmq(j-lf,j-lf+i); if(temp >= lf) res = max(res,temp/i+1); } if(ans < res) { ans = res; num = 0; que[num++] = i; } else if(ans == res) { if(que[num-1] == i) continue; que[num++] = i; } } } int pos,lt; for(i = 1;i <= len;i ++) { for(j = 0;j < num;j ++) { int temp = que[j]; if(rmq(sa[i],sa[i]+temp) >= (ans-1)*temp) { pos = sa[i]; lt = temp*ans; break; } } if(j != num) break; } printf("Case %d: ",cas++); for(i = 0;i < lt;i ++) printf("%c",str[pos+i]); printf("\n"); } return 0; }
很棒的一個題,把一個數字串分爲三部分,翻轉。特別注意第一個數字最大,倒序以後,最小的後綴,必定是最小的數字開頭的,由於最後一個數字爲最大,不存在下面這種狀況。
後面就是分紅兩段的狀況了,選最小並不必定對。
如 5 0 5 0 2 3 倒過來以後 3 2 0 5 0 5
0 5
0 5 0 5
...
這樣選最小的並不必定最好, 0 5 和0 5 0 5前面是同樣的。0 5後面其實要比較後一部分的字典序。
作法看這個博客:http://www.cnblogs.com/zcwwzdjn/archive/2012/03/10/2389413.html
就是再複製一遍,注意保證分紅兩部分sa[i]>=1,這題不用中間隔開字符,要理解思想啊....
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cmath> using namespace std; #define N 201000 int sa[N],height[N],rank[N]; int c[N],wa[N],wb[N]; int p[N],que[N]; int ans[4]; struct node { int x,id; } num[N]; bool cmp(node a,node b) { return a.x < b.x; } void build_sa(int s[],int n,int m) { int i,j,p,*x = wa,*y = wb; for(i = 0; i < m; i ++) c[i] = 0; for(i = 0; i < n; i ++) c[x[i] = s[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]]] = 0; 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]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++; if(p >= n) break; m = p; } } int main() { int n,i,temp,tn; scanf("%d",&n); tn = n; for(i = 0; i < n; i ++) { scanf("%d",&num[i].x); que[n-i-1] = num[i].x; num[i].id = n-i-1; } sort(num,num+n,cmp); temp = 2; p[num[0].id] = 1; for(i = 1; i < n; i ++) { p[num[i].id] = num[i-1].x == num[i].x?temp-1:temp++; } p[n] = 0; build_sa(p,n+1,temp+10); ans[0] = 1000000; for(i = 1; i <= n; i ++) { if(sa[i] >= 2) { ans[1] = sa[i]; break; } } n = ans[1]; for(i = 0; i < ans[1]; i ++) p[n++] = p[i]; p[n] = 0; build_sa(p,n+1,temp+10); for(i = 1; i <= n; i ++) { if(sa[i] < ans[1]&&sa[i] >= 1) { ans[2] = sa[i]; break; } } for(i = ans[1]; i < tn; i ++) printf("%d\n",que[i]); for(i = ans[2]; i < ans[1]; i ++) printf("%d\n",que[i]); for(i = 0; i < ans[2]; i ++) printf("%d\n",que[i]); return 0; }
HDU 4416 Good Article Good sentence
RE了不少次....注意n = 0,數組開小,最後結果LL。
A出現過,B[]沒出現的字串。
論文裏有求子串的個數,這題麻煩一點,後綴排序後對於sa[i] 要減去前面出現過的和後面出現過的。前面出現過的值確定是height[i],不管sa[i-1]是A裏面的,仍是B[]裏面的,height[i]是最大值,保證A#B...保證這個#是字典序是次小的,保證了A的相對順序不變, 再從j+1尋找第一個B[]的後綴,那麼rmq(i+1,pos)就是sa[i]後面出現過的,取 max就好,那個rmq從後往前倒着標記一遍就能夠求出來。
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cmath> using namespace std; #define N 501000 #define LL __int64 int sa[N],height[N],rank[N]; int c[N],wa[N],wb[N]; int p[N]; int res[N]; char str[N]; void build_sa(int s[],int n,int m) { int i,j,p,*x = wa,*y = wb; for(i = 0;i < m;i ++) c[i] = 0; for(i = 0;i < n;i ++) c[x[i] = s[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]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++; if(p >= n) break; m = p; } } void get_height(int s[],int n) { int i,j,k = 0; for(i = 1;i <= n;i ++) rank[sa[i]] = i; for(i = 0;i < n;i ++) { if(k) k--; j = sa[rank[i]-1]; while(s[i+k]==s[j+k]) k ++; height[rank[i]] = k; } } int main() { int t,cas = 1,i,temp,len,tlen,num; int n,j; scanf("%d",&t); while(t--) { scanf("%d",&n); num = 0; for(i = 0;i <= n;i ++) { scanf("%s",str); if(i == 0) len = strlen(str); tlen = strlen(str); for(j = 0;j < tlen;j ++) { p[num++] = str[j]-'a'+2+n; } if(i == n) p[num] = 0; else p[num++] = i+1; } build_sa(p,num+1,n+30); get_height(p,num); LL ans = 0; temp = 0; for(i = num;i >= 1;i --) { if(sa[i] < len) { res[i] = temp; temp = min(height[i],res[i]); } else temp = height[i]; } for(i = 1;i <= num;i ++) { if(sa[i] < len) { ans += len - sa[i] - max(height[i],res[i]); } } printf("Case %d: %I64d\n",cas++,ans); } return 0; }
水題....
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cmath> using namespace std; #define N 1100 #define LL __int64 int sa[N],height[N],rank[N]; int c[N],wa[N],wb[N]; int p[N]; char str[N]; void build_sa(int s[],int n,int m) { int i,j,p,*x = wa,*y = wb; for(i = 0;i < m;i ++) c[i] = 0; for(i = 0;i < n;i ++) c[x[i] = s[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]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++; if(p >= n) break; m = p; } } void get_height(int s[],int n) { int i,j,k = 0; for(i = 1;i <= n;i ++) rank[sa[i]] = i; for(i = 0;i < n;i ++) { if(k) k --; j = sa[rank[i]-1]; while(s[i+k] == s[j+k]) k ++; height[rank[i]] = k; } } int main() { int i,j,len,maxz,minz; while(scanf("%s",str)!=EOF) { if(str[0] == '#') break; len = strlen(str); for(i = 0;i < len;i ++) p[i] = str[i] - 'a' + 1; p[len] = 0; build_sa(p,len+1,30); get_height(p,len); int ans = 0; for(i = 1;i <= len;i ++) { maxz = sa[1]; minz = sa[1]; for(j = 2;j <= len;j ++) { if(height[j] < i) { if(minz+i <= maxz) ans ++; maxz = sa[j]; minz = sa[j]; } else { maxz = max(maxz,sa[j]); minz = min(minz,sa[j]); } } if(minz+i <= maxz) ans ++; } printf("%d\n",ans); } return 0; }
注意n = 1的特殊狀況。
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cmath> using namespace std; #define N 100000 int sa[N],height[N],rank[N]; int c[N],wa[N],wb[N]; int p[N]; char str[N]; int m; void build_sa(int s[],int n,int m) { int i,j,p,*x = wa,*y = wb; for(i = 0; i < m; i ++) c[i] = 0; for(i = 0; i < n; i ++) c[x[i] = s[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]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++; if(p >= n) break; m = p; } } void get_height(int s[],int n) { int i,j,k = 0; for(i = 1; i <= n; i ++) rank[sa[i]] = i; for(i = 0; i < n; i ++) { if(k) k --; j = sa[rank[i]-1]; while(s[i+k] == s[j+k]) k ++; height[rank[i]] = k; } } int judge(int mid,int n) { int i,flag = 1; for(i = 1; i <= n; i ++) { if(height[i] < mid) { if(flag >= m) return 1; flag = 1; } else flag ++; } if(flag >= m) return 1; else return 0; } int main() { int i,len; while(scanf("%d",&m)!=EOF) { if(m == 0) break; scanf("%s",str); len = strlen(str); if(m == 1) { printf("%d %d\n",len,0);//特判 continue; } for(i = 0; i < len; i ++) { p[i] = str[i] - 'a' + 1; } p[len] = 0; build_sa(p,len+1,30); get_height(p,len); int str,end,mid; str = 0; end = len; while(str < end) { mid = (str + end + 1)/2; if(judge(mid,len)) str = mid; else end = mid - 1; } if(end == 0) { printf("none\n"); continue; } printf("%d ",end); int flag = 1,temp = sa[1],ans; ans = 0; for(i = 1; i <= len; i ++) { if(height[i] < end) { if(flag >= m) ans = max(ans,temp); temp = sa[i]; flag = 1; } else { temp = max(temp,sa[i]); flag ++; } } if(flag >= m) ans = max(ans,temp); printf("%d\n",ans); } return 0; }
想了好一會,發現 不會啊。。。。原來看錯題了。。。這個比較只是相鄰的....挺水的....
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cmath> using namespace std; #define N 300000 #define LL __int64 int sa[N],height[N],rank[N]; int c[N],wa[N],wb[N]; int p[N],sum[N]; int minz[22][N]; int bin[22]; char str[N]; void build_sa(int s[],int n,int m) { int i,j,p,*x = wa,*y = wb; for(i = 0;i < m;i ++) c[i] = 0; for(i = 0;i < n;i ++) c[x[i] = s[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]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++; if(p >= n) break; m = p; } } void get_height(int s[],int n) { int i,j,k = 0; for(i = 1;i <= n;i ++) rank[sa[i]] = i; for(i = 0;i < n;i ++) { if(k) k --; j = sa[rank[i]-1]; while(s[i+k] == s[j+k]) k ++; height[rank[i]] = k; } } void init(int n) { int i,j; for(i = 1;i <= n;i ++) minz[0][i] = height[i]; for(i = 1;i <= bin[i];i ++) { for(j = 1;j + bin[i-1] <= n;j ++) { minz[i][j] = min(minz[i-1][j],minz[i-1][j+bin[i-1]]); } } } int rmq(int s,int t) { s = rank[s];t = rank[t]; if(s > t) swap(s,t); s ++; int k = log((t-s+1)*1.0)/log(2.0); return min(minz[k][s],minz[k][t-bin[k]+1]); } int fun(int num) { int ans = 0; if(num == 0) return 1; while(num) { num /= 10; ans ++; } return ans; } int main() { int i,len,n,l,r,pl,pr; for(i = 0;i <= 20;i ++) bin[i] = 1<<i; while(scanf("%s",str)!=EOF) { len = strlen(str); for(i = 0;i < len;i ++) { p[i] = str[i] - 'a' + 1; } p[len] = 0; build_sa(p,len+1,30); get_height(p,len); init(len); scanf("%d",&n); LL ans1,ans2; int num,temp; ans1 = ans2 = 0; pl = pr = 0; for(i = 0;i < n;i ++) { scanf("%d%d",&l,&r); ans1 += r - l + 1; if(pl == l) temp = len - l; else temp = rmq(pl,l); num = min(pr-pl,min(temp,r-l)); ans2 += fun(num) + 2 + r - l - num; pl = l; pr = r; } printf("%I64d %I64d\n",ans1,ans2); } return 0; }