zoukankan      html  css  js  c++  java
  • uva 11107 Life Forms

    题意:给你N个串,求一个串在大于等于N/2的模板串中连续出现。如果有多解按字典序最小输出。

    白书模板题。二分答案+合并模板串成一个新串,扫秒新串的height数组。

    考查后缀数组+LCP

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 using namespace std;
      5 
      6 const int maxn = 1001 * 100 + 10;
      7 
      8 struct SuffixArray
      9 {
     10     int s[maxn];      // 原始字符数组(最后一个字符应必须是0,而前面的字符必须非0)
     11     int sa[maxn];     // 后缀数组
     12     int rank[maxn];   // 名次数组. rank[0]一定是n-1,即最后一个字符
     13     int height[maxn]; // height数组
     14     int t[maxn], t2[maxn], c[maxn]; // 辅助数组
     15     int n; // 字符个数
     16 
     17     void clear()
     18     {
     19         n = 0;
     20         memset(sa, 0, sizeof(sa));
     21     }
     22 
     23     // m为最大字符值加1。调用之前需设置好s和n
     24     void build_sa(int m)
     25     {
     26         int i, *x = t, *y = t2;
     27         for(i = 0; i < m; i++) c[i] = 0;
     28         for(i = 0; i < n; i++) c[x[i] = s[i]]++;
     29         for(i = 1; i < m; i++) c[i] += c[i-1];
     30         for(i = n-1; i >= 0; i--) sa[--c[x[i]]] = i;
     31         for(int k = 1; k <= n; k <<= 1)
     32         {
     33             int p = 0;
     34             for(i = n-k; i < n; i++) y[p++] = i;
     35             for(i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i]-k;
     36             for(i = 0; i < m; i++) c[i] = 0;
     37             for(i = 0; i < n; i++) c[x[y[i]]]++;
     38             for(i = 0; i < m; i++) c[i] += c[i-1];
     39             for(i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
     40             swap(x, y);
     41             p = 1;
     42             x[sa[0]] = 0;
     43             for(i = 1; i < n; i++)
     44                 x[sa[i]] = y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k] ? p-1 : p++;
     45             if(p >= n) break;
     46             m = p;
     47         }
     48     }
     49 
     50     void build_height()
     51     {
     52         int i, j, k = 0;
     53         for(i = 0; i < n; i++) rank[sa[i]] = i;
     54         for(i = 0; i < n; i++)
     55         {
     56             if(k) k--;
     57             int j = sa[rank[i]-1];
     58             while(s[i+k] == s[j+k]) k++;
     59             height[rank[i]] = k;
     60         }
     61     }
     62 };
     63 
     64 const int maxc = 100 + 10; // 串的个数
     65 const int maxl = 1000 + 10; // 每个串的长度
     66 
     67 SuffixArray sa;
     68 int n;
     69 char word[maxl];
     70 int idx[maxn];
     71 int flag[maxc];
     72 
     73 // 子串[L,R) 是否符合要求
     74 bool good(int L, int R)
     75 {
     76     memset(flag, 0, sizeof(flag));
     77     if(R - L <= n/2) return false;
     78     int cnt = 0;
     79     for(int i = L; i < R; i++)
     80     {
     81         int x = idx[sa.sa[i]];
     82         if(x != n && !flag[x])
     83         {
     84             flag[x] = 1;
     85             cnt++;
     86         }
     87     }
     88     return cnt > n/2;
     89 }
     90 
     91 void print_sub(int L, int R)
     92 {
     93     for(int i = L; i < R; i++)
     94         printf("%c", sa.s[i] - 1 + 'a');
     95     printf("
    ");
     96 }
     97 
     98 bool print_solutions(int len, bool print)
     99 {
    100     int L = 0;
    101     for(int R = 1; R <= sa.n; R++)
    102     {
    103         if(R == sa.n || sa.height[R] < len)   // 新开一段
    104         {
    105             if(good(L, R))
    106             {
    107                 if(print) print_sub(sa.sa[L], sa.sa[L] + len);
    108                 else 
    109                     return true;
    110             }
    111             L = R;
    112         }
    113     }
    114     return false;
    115 }
    116 
    117 void solve(int maxlen)
    118 {
    119     if(!print_solutions(1, false))
    120         printf("?
    ");
    121     else
    122     {
    123         int L = 1, R = maxlen, M;
    124         while(L < R)
    125         {
    126             M = L + (R-L+1)/2;
    127             if(print_solutions(M, false)) L = M;
    128             else R = M-1;
    129         }
    130         print_solutions(L, true);
    131     }
    132 }
    133 
    134 // 给字符串加上一个字符,属于字符串i
    135 void add(int ch, int i)
    136 {
    137     idx[sa.n] = i;
    138     sa.s[sa.n++] = ch;
    139 }
    140 
    141 int main()
    142 {
    143     int kase = 0;
    144     while(scanf("%d", &n) == 1 && n)
    145     {
    146         if(kase++ > 0) printf("
    ");
    147         int maxlen = 0;
    148         sa.clear();
    149         for(int i = 0; i < n; i++)
    150         {
    151             scanf("%s", word);
    152             int sz = strlen(word);
    153             maxlen = max(maxlen, sz);
    154             for(int j = 0; j < sz; j++)
    155                 add(word[j] - 'a' + 1, i);
    156             add(100 + i, n); // 结束字符
    157         }
    158         add(0, n);
    159 
    160         if(n == 1) printf("%s
    ", word);
    161         else
    162         {
    163             sa.build_sa(100 + n);
    164             sa.build_height();
    165             solve(maxlen);
    166         }
    167     }
    168     return 0;
    169 }
    View Code
  • 相关阅读:
    1038 Recover the Smallest Number (30分) sort-cmp妙用(用于使字符串序列最小)
    1033 To Fill or Not to Fill (25分)贪心(???)
    1030 Travel Plan (30分) dij模板题
    1020 Tree Traversals (25分)(树的构造:后序+中序->层序)
    1022 Digital Library (30分) hash模拟
    1018 Public Bike Management (30分)(Dijkstra路径保存fa[]+DFS路径搜索)
    1017 Queueing at Bank (25分)模拟:关于事务排队处理
    1014 Waiting in Line (30分)队列模拟题
    1010 Radix (25分)暴力猜数or二分猜数
    HDU 3032 multi-sg 打表找规律
  • 原文地址:https://www.cnblogs.com/ITUPC/p/5046799.html
Copyright © 2011-2022 走看看