zoukankan      html  css  js  c++  java
  • 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:>>>>>>>
    ", (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
    ", (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 }
    View Code
  • 相关阅读:
    (原)Lazarus 异构平台下多层架构思路、DataSet转换核心代码
    (学)新版动态表单研发,阶段成果3
    (学) 如何将 Oracle 序列 重置 清零 How to reset an Oracle sequence
    (学)XtraReport WebService Print 报错
    (原)三星 i6410 刷机 短信 无法 保存 解决 办法
    (原) Devexpress 汉化包 制作工具、测试程序
    linux下网络配置
    apache自带ab.exe小工具使用小结
    Yii::app()用法小结
    PDO使用小结
  • 原文地址:https://www.cnblogs.com/rootial/p/3940638.html
Copyright © 2011-2022 走看看