• UVALive


      题意:找一个出现了m次的最长子串,以及这时的最右的位置。

      hash的话代码还是比较好写的,,但是时间比SA多很多。。

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <string.h>
     4 using namespace std;
     5 const int N = 40000 + 100;
     6 typedef long long ll;
     7 const int X = 257;
     8 const int mod = (int)1e9 + 7;
     9 
    10 char s[N];
    11 int m,len,pw[N];
    12 int H[N],pos;
    13 
    14 struct node
    15 {
    16     int id,hash;
    17     bool operator < (const node & temp) const
    18     {
    19         return hash == temp.hash ? id < temp.id : hash < temp.hash;
    20     }
    21 }p[N];
    22 
    23 bool solve(int L)
    24 {
    25     int cnt = 0;
    26     pos = -1;
    27     for(int i=1;i+L-1<=len;i++)
    28     {
    29         int id = i;
    30         int hash = ((ll)H[i] - (ll)H[i+L]*pw[L]) % mod;
    31         if(hash < 0) hash += mod; // 注意这里!
    32         p[i] = (node){id, hash};
    33     }
    34     sort(p+1, p+1+ len - L + 1);
    35 
    36     for(int i=1;i<=len-L+1;i++)
    37     {
    38         if(i == 1 || p[i].hash != p[i-1].hash) cnt = 0;
    39         if(++cnt >= m) pos = max(pos, p[i].id);
    40     }
    41     return pos != -1;
    42 }
    43 
    44 int main()
    45 {
    46     pw[0] = 1;
    47     for(int i=1;i<N;i++) pw[i] = 1LL*pw[i-1] * X % mod;
    48     while(scanf("%d",&m) == 1 && m)
    49     {
    50         scanf("%s",s+1);
    51         len = strlen(s+1);
    52         for(int i=len;i>=1;i--) H[i] = (1LL*H[i+1] * X + s[i] - 'a') % mod;
    53         int l = 1, r = len, ans = -1;
    54         while(l <= r)
    55         {
    56             int mid = l + r >> 1;
    57             if(solve(mid)) ans = mid, l = mid + 1;
    58             else r = mid - 1;
    59         }
    60         solve(ans);
    61         if(ans != -1) printf("%d %d
    ",ans, pos-1);
    62         else puts("none");
    63     }
    64     return 0;
    65 }
    hash的写法

      

      SA的话,写法需要细细体会一下了。。时间减少了很多。

      1 #include <stdio.h>
      2 #include <algorithm>
      3 #include <string.h>
      4 using namespace std;
      5 const int N = 40000 + 100;
      6 typedef long long ll;
      7 
      8 /**
      9  *    sa[i]:表示排在第i位的后缀的起始下标
     10  *    rank[i]:表示后缀suffix(i)排在第几
     11  *    height[i]:sa[i-1] 与 sa[i]的LCP(最长公共前缀)值
     12  *
     13  * */
     14  /*
     15     如果整数的话模板改成int.
     16     加一个数a[n] = 0 。 这样他的排名是第一个。
     17     construct(a,n+1);
     18 
     19     字符串的话。
     20     len = strlen(str);
     21     construct(s,strlen(s)+1);
     22     排名第0的是个空字符串。
     23 
     24     height[i]:sa[i-1] 与 sa[i]的LCP(最长公共前缀)值
     25     所以height[1] = 0;
     26     rank[len] = 0;
     27     sa[0] = len;
     28  */
     29 int sa[N],rnk[N],height[N];
     30 void construct(const char *s,int n,int m = 256) {
     31     static int t1[N],t2[N],c[N];
     32     int *x = t1,*y = t2;
     33     int i,j,k,p,l;
     34     for (i = 0; i < m; ++ i) c[i] = 0;
     35     for (i = 0; i < n; ++ i) c[x[i] = s[i]] ++;
     36     for (i = 1; i < m; ++ i) c[i] += c[i - 1];
     37     for (i = n - 1; i >= 0; -- i) sa[--c[x[i]]] = i;
     38     for (k = 1; k <= n; k <<= 1) {
     39         p = 0;
     40         for (i = n - k; i < n; ++ i) y[p++] = i;
     41         for (i = 0; i < n; ++ i) if (sa[i] >= k) y[p++] = sa[i] - k;
     42         for (i = 0; i < m; ++ i) c[i] = 0;
     43         for (i = 0; i < n; ++ i) c[x[y[i]]] ++;
     44         for (i = 1; i < m; ++ i) c[i] += c[i - 1];
     45         for (i = n - 1; i >= 0; -- i) sa[--c[x[y[i]]]] = y[i];
     46         std::swap(x,y);
     47         p = 1; x[sa[0]] = 0;
     48         for (i = 1; i < n; ++ i)
     49             x[sa[i]] = y[sa[i - 1]] == y[sa[i]]
     50                 && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1: p ++;
     51         if (p >= n) break;
     52         m = p;
     53     }
     54     for (i = 0; i < n; ++ i) rnk[sa[i]] = i;
     55     for (i = 0,l = 0; i < n; ++ i) {
     56         if (rnk[i]) {
     57             j = sa[rnk[i] - 1];
     58             while (s[i + l] == s[j + l]) l++;
     59             height[rnk[i]] = l;
     60             if (l) l--;
     61         }
     62     }
     63 }
     64 
     65 int m,pos,len;
     66 char s[N];
     67 bool solve(int L)
     68 {
     69     // 用后缀数组的话,如果重复长度就是最长的长度,需要特判
     70     if(m == 1 && L == len) {pos = 0; return 1;}
     71     pos = -1;
     72     int cnt = 1;
     73     int temp = -1; // 要用一个temp来记录当前cnt>=m的最大的位置
     74     for(int i=1;i<=len;i++)
     75     {
     76         if(height[i] >= L) cnt++, temp = max(temp, sa[i]);
     77         else cnt = 1, temp = sa[i];
     78         if(cnt >= m) pos = max(pos, temp);
     79     }
     80     return pos != -1;
     81 }
     82 
     83 int main()
     84 {
     85     while(scanf("%d",&m) == 1 && m)
     86     {
     87         scanf("%s",s);
     88         len = strlen(s);
     89         construct(s, len+1);
     90         int l = 1, r = len;
     91         int ans = -1;
     92         while(l <= r)
     93         {
     94             int mid = l + r >> 1;
     95             if(solve(mid)) ans = mid, l = mid + 1;
     96             else r = mid - 1;
     97         }
     98         solve(ans);
     99         if(ans != -1) printf("%d %d
    ",r,pos);
    100         else puts("none");
    101     }
    102     return 0;
    103 }
    SA的写法

      顺便想说一下的是,这里不知为何下标从1开始无限WA,以后用SA还是下标从0开始好了。。毕竟不懂SA的具体原理。

  • 相关阅读:
    团队管理-每日站会,代码审查,结对编程
    Linux awk命令详解
    【Vegas原创】Excel中,日期和时间用&连接后格式不正确的解决方法
    SQLServer 数据库变成单个用户后无法访问问题的解决方法
    【Vegas原创】查询SQL Server更改记录的语句
    【Vegas原创】SQL Server 只安装客户端的方法
    IT? 挨踢
    64位Windows无法打开会声会影X5的解决方法
    小型IT部门建设之我见
    要熟练掌握的七个人生工具
  • 原文地址:https://www.cnblogs.com/zzyDS/p/6189539.html
Copyright © 2020-2023  润新知