zoukankan      html  css  js  c++  java
  • [acm/icpc2016ChinaFinal][CodeforcesGym101194] Mr. Panda and Fantastic Beasts

    地址:http://codeforces.com/gym/101194

    题目:略

    思路:

      这题做法挺多的,可以sam也可以后缀数组,我用sam做的。

      1.我自己yy的思路(瞎bb的

        把第一个串建立sam,然后让其他串在上面跑。

        每走到一个位置p,当前长度为num,就代表这个endpos集合里的长度小于等于num的字符串是被包含了,同时parent树的所有祖先节点也要标记为被包含。

        这一步的具体做法是:用一个mi数组表示到达该节p点时的长度大于mi[p]时,才算未被包含(到达长度指的是从root出发经过某条路径到p的长度),所以其他串在sam上走到每个节点p,长度为num时,记录下mi[p]=max(mi[p],num);

        再跑完所有串后,来更新parent树上的节点。先拓扑排序,然后如果mi[p]>0,mi[fa[p]]=len[p],否则mi[p]=len[fa[p]]。(mi数组初始时为0)

        这样可以在O(n)更新parent树.

        然后再扫一遍节点,如果mi[p]<len[p],anslen=min(anslen,mi[p]+1),这样就得到了anslen。(anslen为最小串的长度)

        在扫一遍节点把所有可行答案求个字典序最小的就行了。(这一步远远没有O(anslen*|p|),p是可行答案集合的大小,时间复杂度可以看下一个做法的时间)

      2.网上看到的做法

        把其他串建立广义sam,然后让第一个串在上面跑。

        这样每当失配的时候,沿parent树走到符合条件的节点p,则此时最小可行字符串长度为len[fa[p]]+2,拿他去更新答案即可。

        这做法时间复杂度更高,因为字符串比较次数比做法一多(它可能比较了长度大于anslen的字符串),且建立sam的时间复杂度也高。

    贴个做法2的代码把,一的不想写了

      1 #include <bits/stdc++.h>
      2 
      3 using namespace std;
      4 
      5 struct SAM
      6 {
      7     static const int MAXN = 1000001<<1;//大小为字符串长度两倍
      8     static const int LetterSize = 26;
      9 
     10     int tot, last, ch[MAXN][LetterSize], fa[MAXN], len[MAXN];
     11     int sum[MAXN], tp[MAXN], cnt[MAXN]; //sum,tp用于拓扑排序,tp为排序后的数组
     12 
     13     void init( void)
     14     {
     15         last = tot = 1;
     16         len[1] = 0;
     17         memset( ch[1], 0, sizeof ch[1]);
     18     }
     19 
     20     void add( int x)
     21     {
     22         int p = last, np = last = ++tot;
     23         len[np] = len[p] + 1, cnt[last] = 1;
     24         memset( ch[np], 0, sizeof ch[np]);
     25         while( p && !ch[p][x]) ch[p][x] = np, p = fa[p];
     26         if( p == 0)
     27             fa[np] = 1;
     28         else
     29         {
     30             int q = ch[p][x];
     31             if( len[q] == len[p] + 1)
     32                 fa[np] = q;
     33             else
     34             {
     35                 int nq = ++tot;
     36                 memcpy( ch[nq], ch[q], sizeof ch[q]);
     37                 len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
     38                 while( p && ch[p][x] == q)  ch[p][x] = nq, p = fa[p];
     39             }
     40         }
     41     }
     42 
     43     void toposort( void)
     44     {
     45         for(int i = 1; i <= len[last]; i++)   sum[i] = 0;
     46         for(int i = 1; i <= tot; i++)   sum[len[i]]++;
     47         for(int i = 1; i <= len[last]; i++)   sum[i] += sum[i-1];
     48         for(int i = 1; i <= tot; i++)   tp[sum[len[i]]--] = i;
     49     }
     50 
     51     void go(char *ss)
     52     {
     53         int mi=0x3f3f3f3f,l;
     54         for(int i=0,p=1,num=0,slen=strlen(ss);i<slen;i++)
     55         {
     56             int c=ss[i]-'a';
     57             if(ch[p][c])    p=ch[p][c],num++;
     58             else
     59             {
     60                 while(p&&!ch[p][c]) p=fa[p];
     61                 if(p)
     62                     num=len[p]+1,p=ch[p][c];
     63                 else
     64                     p=1,num=0;
     65                 if(num+1<mi)    mi=num+1,l=i-num;
     66                 else if(num+1==mi)
     67                 for(int j=l,k=i-num;k<=i;k++,j++)
     68                 if(ss[j]!=ss[k])
     69                 {
     70                     if(ss[j]>ss[k]) l=i-num;
     71                     break;
     72                 }
     73             }
     74         }
     75         if(mi==0x3f3f3f3f)
     76             printf("Impossible");
     77         else
     78             for(int i=0;i<mi;i++)
     79                 printf("%c",ss[i+l]);
     80     }
     81 } sam;
     82 
     83 char sa[1000000],sb[1000000];
     84 int main(void)
     85 {
     86     int t,n,cs=1;cin>>t;
     87     while(t--)
     88     {
     89         sam.init();
     90         scanf("%d%s",&n,sa);
     91         for(int i=1;i<n;i++)
     92         {
     93             scanf("%s",sb);
     94             for(char *p=sb;*p;p++)  sam.add(*p-'a');
     95             sam.last=1;
     96         }
     97         printf("Case #%d: ",cs++);
     98         sam.go(sa);
     99         printf("
    ");
    100     }
    101     return 0;
    102 }
  • 相关阅读:
    内存溢出异常
    Java堆中的对象
    运行时数据区域
    字符串常量池
    自己编译JDK
    @PathVariable注解详解
    spring容器监听器
    redis和spring整合
    Redis安装、启动、关闭
    HDU3974 Assign the task
  • 原文地址:https://www.cnblogs.com/weeping/p/7592008.html
Copyright © 2011-2022 走看看