首页 > 代码库 > Uva 12361 File Retrieval 后缀数组+并查集
Uva 12361 File Retrieval 后缀数组+并查集
题意:有F个单词,1 <= F <=60 , 长度<=10^4, 每次可以输入一个字符串,所有包含该字串的单词会形成一个集合。
问最多能形成多少个不同的集合。集合不能为空。
分析:用后缀数组处理。然后首先考虑一个单词形成一个集合的情况,若该单词是其他单词的字串,则该单词显然不会形成一个集合,那么利用后缀数组,
对于每个单词看能否与其他单词有LCP,且LCP 长度为该单词本身长度。
然后就是多个单词形成集合的情况:比较简单的处理方式就是将h数组值相同的下标集中存储,比如h[x] = h[y] = h[z] = 5, 那么将x,y,z存到h
值对应为5的数组中,然后按照h值,假设为v,从大到小的顺序,将所有h值为v的下标与其周围的LCP大于v的(h[v-1],h[v])对应的子串,更新并查集。实际意义就是,每次将h值为h[v]的一些子串所在的单词合并到之前h值> h[v]的子串所在的单词形成的并查集中,得到的并查集中单词一定有长度>=h[v]公共字串,这样的并查集实际就是一个合法的单词集合,可以利用二进制表示,每次得到新的集合则将二进制表示加入到统计集合的set中,最后结果就是set的大小。
AC代码其实是比赛时写的,当时多个单词部分不是上面这种写法,不过类似。
1 #include <bits/stdc++.h> 2 #define in freopen("solve_in.txt", "r", stdin); 3 #define bug(x) printf("Line %d:>>>>>>>\n", (x)); 4 5 #define REV(a) reverse((a).begin(), (a).end()) 6 #define READ(a, n) {REP(i, n) cin>>(a)[i];} 7 #define REP(i, n) for(int i = 0; i < (n); i++) 8 #define VREP(i, n, base) for(int i = (n); i >= (base); i--) 9 #define Rep(i, base, n) for(int i = (base); i < (n); i++) 10 #define REPS(s, i) for(int i = 0; (s)[i]; i++) 11 using namespace std; 12 typedef unsigned long long ULL; 13 typedef long long LL; 14 typedef map<ULL, int> UMps; 15 set<ULL> se; 16 17 const int maxn = 10500 + 100; 18 const int maxm = 66; 19 const int maxlen = maxn*maxm+100; 20 int s[maxlen]; 21 int sa[maxlen], t[maxlen], t2[maxlen], c[maxlen], n, m, dp[maxlen][30]; 22 int num[maxlen]; 23 LL ans; 24 void build_sa(int m) { 25 int *x = t, *y = t2; 26 27 REP(i, m) c[i] = 0; 28 REP(i, n) c[x[i] = s[i]]++; 29 Rep(i, 1, m) c[i] += c[i-1]; 30 VREP(i, n-1, 0) sa[--c[x[i]]] = i; 31 32 for(int k = 1; k <= n; k <<= 1) { 33 int p = 0; 34 35 Rep(i, n-k, n) y[p++] = i; 36 REP(i, n) if(sa[i] >= k) y[p++] = sa[i]-k; 37 38 REP(i, m) c[i] = 0; 39 REP(i, n) c[x[y[i]]]++; 40 Rep(i, 1, m) c[i] += c[i-1]; 41 42 VREP(i, n-1, 0) sa[--c[x[y[i]]]] = y[i]; 43 swap(x, y); 44 p = 1, x[sa[0]] = 0; 45 Rep(i, 1, n) 46 x[sa[i]] = y[sa[i-1]] == y[sa[i]] && y[sa[i-1]+k] == y[sa[i]+k] ? p-1 : p++; 47 if(p >= n) break; 48 m = p; 49 } 50 } 51 int rk[maxlen], h[maxlen]; 52 53 void getHeight() { 54 int j, k = 0; 55 h[0] = 0; 56 REP(i, n) rk[sa[i]] = i; 57 REP(i, n) { 58 if(k) k--; 59 if(rk[i] == 0) 60 continue; 61 j = sa[rk[i]-1]; 62 while( s[i+k] == s[j+k]) k++; 63 h[rk[i]] = k; 64 } 65 } 66 void RMQ_init() { 67 REP(i, n) dp[i][0] = h[i]; 68 for(int k = 1; (1<<k) <= n; k++) 69 for(int i = 0; i + (1<<k) <= n; i++) 70 dp[i][k] = min(dp[i][k-1], dp[i+(1<<(k-1))][k-1]); 71 } 72 int RMQ(int l, int r) { 73 int k = 0; 74 while((1<<(k+1)) <= r-l+1) k++; 75 return min(dp[l][k], dp[r-(1<<k)+1][k]); 76 } 77 char word[maxm][maxn]; 78 int nn; 79 inline int idx(char ch) { 80 return ch-‘a‘+1; 81 } 82 int vis[70], slen[70]; 83 84 void solveSingle() { 85 se.clear(); 86 memset(vis, 0, sizeof vis); 87 for(int i = 1; i < n; i++){ 88 if(h[i]){ 89 if(num[sa[i]] != -1 && h[i] == slen[num[sa[i]]]) 90 vis[num[sa[i]]] = 1; 91 if(num[sa[i-1]] != -1 && h[i] == slen[num[sa[i-1]]]) 92 vis[num[sa[i-1]]] = 1; 93 } 94 } 95 for(int i = 0; i < nn; i++) if(!vis[i]) 96 se.insert(1ULL<<i); 97 } 98 void dfs(int l, int r, int now) { 99 if(l >= r)100 return;101 ULL tmp;102 103 for(int i = l; i < r; ) {104 tmp = 0;105 while(i < r && h[i] <= now)106 i++;107 if(i >= r)108 break;109 int mx = (int)1e9;110 int j = i;111 mx = min(mx, h[j]);112 if(j < r && num[sa[j-1]] != -1)113 tmp |= 1ULL<<num[sa[j-1]];114 while(j < r && h[j] > now) {115 mx = min(mx, h[j]);116 if(num[sa[j]] != -1)117 tmp |= 1ULL<<num[sa[j]];118 j++;119 }120 if(tmp)121 se.insert(tmp);122 dfs(i, j, mx);123 i = j;124 }125 }126 void solve() {127 build_sa(120);128 getHeight();129 solveSingle();130 ULL tmp;131 for(int i = 1; i < n; ) {132 int mx = (int)1e9;133 tmp = 0;134 while(i < n && !h[i])135 i++;136 if(i >= n)137 break;138 mx = min(mx, h[i]);139 int j = i;140 if(j < n && num[sa[j-1]] != -1)141 tmp |= 1ULL<<num[sa[j-1]];142 while(j < n && h[j]) {143 mx = min(mx, h[j]);144 if(num[sa[j]] != -1)145 tmp |= 1ULL<<num[sa[j]];146 j++;147 }148 if(tmp)149 se.insert(tmp);150 dfs(i, j, mx);151 i = j;152 }153 printf("%llu\n", (ULL)se.size());154 }155 int main() {156 157 158 while(scanf("%d", &nn), nn) {159 n = 0;160 memset(num, -1, sizeof num);161 for(int i = 0; i < nn; i++) {162 slen[i] = 0;163 scanf("%s", word[i]);164 for(int j = 0; word[i][j]; j++) {165 slen[i]++;166 s[n] = idx(word[i][j]);167 num[n++] = i;168 }169 s[n++] = 30+i;170 }171 s[n-1] = 0;172 solve();173 }174 return 0;175 }
Uva 12361 File Retrieval 后缀数组+并查集
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。