Jerry_Black

Untitled

Apr 21st, 2023
158
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.86 KB | None | 0 0
  1. #include<algorithm>
  2. #include<cassert>
  3. #include<cctype>
  4. #include<cmath>
  5. #include<cstdio>
  6. #include<cstring>
  7. #include<functional>
  8. #include<iomanip>
  9. #include<iostream>
  10. #include<map>
  11. #include<math.h>
  12. #include<queue>
  13. #include<set>
  14. #include<sstream>
  15. #include<stack>
  16. #include<string>
  17. #include<utility>
  18. #include<vector>
  19. using namespace std;
  20.  
  21. #define ll long long
  22. //#define int ll
  23.  
  24. const int inf=0x3f3f3f3f;
  25. const ll INF=0x3f3f3f3f3f3f3f3f;
  26.  
  27. const int MAXLEN = 1000005;
  28. struct SAIS
  29. {
  30.     // 后缀类型
  31. #define L_TYPE 0
  32. #define S_TYPE 1
  33.    
  34.     int st[MAXLEN];
  35.     int rl[MAXLEN],rk[MAXLEN],lcp[MAXLEN];
  36.     int n;
  37.     //rl:后缀排序后的排名列表,rl[i]代表第i名的后缀的序号
  38.     //rk:名次,rk[i]代表后缀i的名次
  39.     //lcp:height数组,lcp[i]代表列表中第i个后缀和第i-1个后缀的lcp长度
  40.    
  41.     void init(const string&s,const int&_n)
  42.     {
  43.         n = _n;
  44.         for (int i=1;i<=n;++i) st[i] = s[i-1];
  45.         // st中的字符必须调成正数!!!!!!!!!!!!!!
  46.     }
  47.    
  48.     // 判断一个字符是否为LMS字符
  49.     inline bool is_lms_char(int *type, int x) {
  50.         return x > 1 && type[x] == S_TYPE && type[x - 1] == L_TYPE;
  51.     }
  52.    
  53.     // 判断两个LMS子串是否相同
  54.     inline bool equal_substring(int *S, int x, int y, int *type) {
  55.         do {
  56.             if (S[x] != S[y])
  57.                 return false;
  58.             x++, y++;
  59.         } while (!is_lms_char(type, x) && !is_lms_char(type, y));
  60.        
  61.         return S[x] == S[y] && type[x] == type[y];
  62.     }
  63.    
  64.     // 诱导排序(从*型诱导到L型、从L型诱导到S型)
  65.     // 调用之前应将*型按要求放入SA中
  66.     inline void induced_sort(int *S, int *SA, int *type, int *bucket, int *lbucket,
  67.                              int *sbucket, int nn, int SIGMA) {
  68.         for (int i = 1; i <= nn; i++)
  69.             if (SA[i] > 1 && type[SA[i] - 1] == L_TYPE)
  70.                 SA[lbucket[S[SA[i] - 1]]++] = SA[i] - 1;
  71.         for (int i = 0; i <= SIGMA; i++)  // Reset S-type bucket
  72.             sbucket[i] = bucket[i];
  73.         for (int i = nn; i >= 1; i--)
  74.             if (SA[i] > 1 && type[SA[i] - 1] == S_TYPE)
  75.                 SA[sbucket[S[SA[i] - 1]]--] = SA[i] - 1;
  76.     }
  77.    
  78.     // SA-IS主体
  79.     // S是输入字符串,length是字符串的长度, SIGMA是字符集的大小
  80.     int *sais(int *S, int length, int SIGMA) {
  81.         int nn = length;
  82.         assert(S[nn]==0);
  83.         int *type = new int[nn + 5];  // 后缀类型
  84.         int *position = new int[nn + 5];  // 记录LMS子串的起始位置
  85.         int *name = new int[nn + 5];  // 记录每个LMS子串的新名称
  86.         int *SA = new int[nn + 5];  // SA数组
  87.         int *bucket = new int[SIGMA + 5];  // 每个字符的桶
  88.         int *lbucket = new int[SIGMA + 5];  // 每个字符的L型桶的起始位置
  89.         int *sbucket = new int[SIGMA + 5];  // 每个字符的S型桶的起始位置
  90.        
  91.         // 初始化每个桶
  92.         memset(bucket, 0, sizeof(int) * (SIGMA + 5));
  93.         for (int i = 1; i <= nn; i++)
  94.             bucket[S[i]]++;
  95.         for (int i = 0; i <= SIGMA; i++) {
  96.             if (i==0)
  97.             {
  98.                 bucket[i] = bucket[i];
  99.                 lbucket[i] = 1;
  100.             }else
  101.             {
  102.                 bucket[i] += bucket[i - 1];
  103.                 lbucket[i] = bucket[i - 1] + 1;
  104.             }
  105.             sbucket[i] = bucket[i];
  106.         }
  107.        
  108.         // 确定后缀类型(利用引理2.1)
  109.         type[nn] = S_TYPE;
  110.         for (int i = nn - 1; i >= 1; i--) {
  111.             if (S[i] < S[i + 1])
  112.                 type[i] = S_TYPE;
  113.             else if (S[i] > S[i + 1])
  114.                 type[i] = L_TYPE;
  115.             else
  116.                 type[i] = type[i + 1];
  117.         }
  118.         // 寻找每个LMS子串
  119.         int cnt = 0;
  120.         for (int i = 1; i <= nn; i++)
  121.             if (is_lms_char(type,i))
  122.                 position[++cnt] = i;
  123.         // 对LMS子串进行排序
  124.         fill(SA, SA + nn + 3, -1);
  125.         for (int i = 1; i <= cnt; i++)
  126.             SA[sbucket[S[position[i]]]--] = position[i];
  127.         induced_sort(S, SA, type, bucket, lbucket, sbucket, nn, SIGMA);
  128.        
  129.         // 为每个LMS子串命名
  130.         fill(name, name + nn + 3, -1);
  131.         int lastx = -1, namecnt = 1;  // 上一次处理的LMS子串与名称的计数
  132.         bool flag = false;  // 这里顺便记录是否有重复的字符
  133.         for (int i = 2; i <= nn; i++) {
  134.             int x = SA[i];
  135.            
  136.             if (is_lms_char(type, x)) {
  137.                 if (lastx >= 0 && !equal_substring(S, x, lastx, type))
  138.                     namecnt++;
  139.                 // 因为只有相同的LMS子串才会有同样的名称
  140.                 if (lastx >= 0 && namecnt == name[lastx])
  141.                     flag = true;
  142.                
  143.                 name[x] = namecnt;
  144.                 lastx = x;
  145.             }
  146.         }  // for
  147.         name[nn] = 0;
  148.        
  149.         // 生成S1
  150.         int *S1 = new int[cnt+5];
  151.         int pos = 0;
  152.         for (int i = 1; i <= nn; i++)
  153.             if (name[i] >= 0)
  154.                 S1[++pos] = name[i];
  155.         int *SA1;
  156.         if (!flag) {
  157.             // 直接计算SA1
  158.             SA1 = new int[cnt + 5];
  159.            
  160.             for (int i = 1; i <= cnt; i++)
  161.                 SA1[S1[i]+1] = i;
  162.         } else
  163.             SA1 = sais(S1, cnt, namecnt);  // 递归计算SA1
  164.        
  165.         // 从SA1诱导到SA
  166.         for (int i = 0; i <= SIGMA; i++) {
  167.             if (i==0)
  168.                 lbucket[i] = 1;
  169.             else
  170.                 lbucket[i] = bucket[i - 1] + 1;
  171.             sbucket[i] = bucket[i];
  172.         }
  173.         fill(SA, SA + nn + 3, -1);
  174.         for (int i = cnt; i >= 1; i--)  // 这里是逆序扫描SA1,因为SA中S型桶是倒序的
  175.             SA[sbucket[S[position[SA1[i]]]]--] = position[SA1[i]];
  176.         induced_sort(S, SA, type, bucket, lbucket, sbucket, nn, SIGMA);
  177.        
  178.         delete[] S1;
  179.         delete[] SA1;
  180.         delete[] bucket;
  181.         delete[] lbucket;
  182.         delete[] sbucket;
  183.         delete[] position;
  184.         delete[] type;
  185.         delete[] name;
  186.         // 后缀数组计算完毕
  187.         return SA;
  188.     }
  189.    
  190.     void build()
  191.     {
  192.         st[0]=st[n+2]=-1;
  193.         st[n+1]=0;
  194.         int SIGMA = 0;
  195.         for (int i=1;i<=n;++i) SIGMA = max(SIGMA,st[i]);
  196.         int * sa = sais(st,n+1,SIGMA);
  197.         for (int i=2;i<=n+1;++i) rk[sa[i]]=i-1;
  198.         delete[] sa;
  199.         for (int i=1;i<=n;++i) rl[rk[i]]=i;
  200.         for (int i=1,len=0;i<=n;++i)
  201.         {
  202.             if (len) --len;
  203.             while (i+len<=n && rl[rk[i]-1]+len<=n && st[i+len]==st[rl[rk[i]-1]+len]) ++len;
  204.             lcp[rk[i]]=len;
  205.         }
  206.     }
  207.  
  208. #undef L_TYPE
  209. #undef R_TYPE
  210. }sa;
  211. char s[MAXLEN];
  212. char ch[105];
  213. int id[MAXLEN];
  214.  
  215. void solve()
  216. {
  217.     int n;
  218.     scanf("%d",&n);
  219.     int len=0;
  220.     int minn=inf;
  221.     for(int i=1;i<=n;i++)
  222.     {
  223.         scanf("%s",s+len);
  224.         int k=(int)strlen(s+len);
  225.         for(int j=0;j<k;j++)id[len+j+1]=i;
  226.         len+=k;
  227.         s[len]=ch[i];
  228.         id[len+1]=0;
  229.         len++;
  230.         minn=min(minn,k);
  231.     }
  232.     s[len]='\0';
  233.     sa.init(s,len);
  234.     sa.build();
  235.     int l=0,r=minn;
  236.     while(l<r)
  237.     {
  238.         int mid=(l+r+1)>>1;
  239.         int ck=0;
  240.         for(int i=1;i<=len;i++)
  241.         {
  242.             if(!id[sa.rl[i]])continue;
  243.             int j=i+1;
  244.             vector<int>min_id(n+1,inf),max_id(n+1,0),vis(n+1);
  245.             min_id[id[sa.rl[i]]]=min(min_id[id[sa.rl[i]]],sa.rl[i]);
  246.             max_id[id[sa.rl[i]]]=max(max_id[id[sa.rl[j]]],sa.rl[i]);
  247.             vis[id[sa.rl[i]]]++;
  248.             while(j<=len&&sa.lcp[j]>=mid)
  249.             {
  250.                 min_id[id[sa.rl[j]]]=min(min_id[id[sa.rl[j]]],sa.rl[j]);
  251.                 max_id[id[sa.rl[j]]]=max(max_id[id[sa.rl[j]]],sa.rl[j]);
  252.                 vis[id[sa.rl[j]]]++;
  253.                 j++;
  254.             }
  255.             int ckk=1;
  256.             for(int k=1;k<=n;k++)
  257.             {
  258.                 if(vis[k]<2||min_id[k]+mid-1>=max_id[k]){ckk=0;break;}
  259.             }
  260.             if(ckk){ck=1;break;}
  261.             i=j-1;
  262.         }
  263.         if(ck)l=mid;
  264.         else r=mid-1;
  265.     }
  266.     printf("%d\n",l);
  267. }
  268.  
  269. signed main()
  270. {
  271. //  ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
  272.  
  273.     for(int i=1;i<=96;i++)ch[i]=(char)i;
  274.     for(int i=97;i<=100;i++)ch[i]=(char)i+26;
  275.  
  276.     int _;scanf("%d",&_);while(_--)
  277.         solve();
  278.     return 0;
  279. }
Advertisement
Add Comment
Please, Sign In to add comment