题目链接$\newcommand{\LCP}{\mathrm{LCP}}\newcommand{\suf}{\mathrm{suf}}$

题意

给定 $n$ 个字符串 $s_1, s_2, \dots, s_n$,求只在 $s_1$ 中出现过的最短子串,若有多解,输出字典序最小的。

分析

为了方便, 称只在 $s_1$ 中出现过的子串为「特殊子串」,记「字符串 $s$ 是字符串 $t$ 的子串」作 $ s \sqsubseteq t$ 。

引理 1

若 $s'$ 是特殊子串,若字符串 $s$ 满足 $s \sqsubseteq s_1$ 且 $s' \sqsubseteq s$,那么 $s$ 也是特殊子串。

因此可二分答案。

问题化为: 判断是否存在长为 $x~(x \le |s_1|)$ 的特殊子串.

用后缀数组解决上述判定问题

  1. 将 $s_1, s_2, \dots, s_n$ 用 未在原串中出现过各不相同 的字符链接成一个长串 $s$ , 构造 $s$ 的后缀数组 $\suf_1, \suf_2, \dots, \suf_i, \dots$ 和 height 数组 $h_1, h_2, \dots, h_i, \dots$ .
  2. 寻找后缀数组中满足如下条件的连续段 $\suf_i, \suf_{i+1}, \dots, \suf_j, \dots, \suf_{i+k-1}$.
    1. $\suf_j$ 起始于 $s_1$ 中
    2. $|\suf_j \sqcap s_1| \ge x$
    3. $|\LCP(\suf_{j_1}, \suf_{j_2})| \ge x$, $\LCP(s, t)$ 指字符串 $s, t$ 的最长公共前缀 (Longest Common Prefix)
    4. $h_i<x$ 且 $h_{i+k}<x$

存在长为 $x$ 的特殊子串 $\Longleftrightarrow$ 存在上述连续段

Implementation

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int N=3e5+5;
  4. char s[N];
  5. int a[N];
  6. int suf[N], suf2[N], rk[N], cnt[N], h[N];
  7. void SA(int *s, int n, int m, int *suf, int *suf2, int *rk, int *cnt){
  8. for(int i=0; i<m; i++)
  9. cnt[i]=0;
  10. for(int i=0; i<n; i++)
  11. cnt[rk[i]=s[i]]++;
  12. for(int i=1; i<m; i++)
  13. cnt[i]+=cnt[i-1];
  14. for(int i=n-1; i>=0; i--)
  15. suf[--cnt[rk[i]]]=i;
  16. for(int len=1; len<n; len<<=1){
  17. int tail=0;
  18. for(int i=n-len; i<n; i++)
  19. suf2[tail++]=i;
  20. for(int i=0; i<n; i++)
  21. if(suf[i]>=len) suf2[tail++]=suf[i]-len;
  22. for(int i=0; i<m; i++)
  23. cnt[i]=0;
  24. for(int i=0; i<n; i++)
  25. cnt[rk[i]]++;
  26. for(int i=1; i<m; i++)
  27. cnt[i]+=cnt[i-1];
  28. for(int i=n-1; i>=0; i--)
  29. suf[--cnt[rk[suf2[i]]]]=suf2[i];
  30. swap(suf2, rk);
  31. auto same=[suf2, len](int i, int j){
  32. return suf2[i]==suf2[j] && suf2[i+len]==suf2[j+len];
  33. };
  34. rk[suf[0]]=0;
  35. for(int i=1; i<n; i++)
  36. rk[suf[i]]=rk[suf[i-1]]+!same(suf[i], suf[i-1]);
  37. m=rk[suf[n-1]]+1;
  38. if(m==n) break;
  39. }
  40. }
  41. void calc(int *a, int *suf, int n, int *rk, int *h){
  42. for(int i=0; i<n; i++)
  43. rk[suf[i]]=i;
  44. for(int i=0, lcp=0; i<n-1; i++){
  45. if(lcp) --lcp;
  46. for(int j=suf[rk[i]-1]; a[j+lcp]==a[i+lcp]; lcp++);
  47. h[rk[i]]=lcp;
  48. }
  49. }
  50. int ok(int x, int len0, int len, int *h){
  51. //two-pointers
  52. for(int i=1; i<=len; i++){ //tricky
  53. if(suf[i]<len0 && suf[i]+x <= len0 && h[i]<x){ //error-prone
  54. for(++i; i<=len && h[i]>=x && suf[i]<len0; i++);
  55. if(i>len || h[i]<x){
  56. assert(suf[i-1]>=0);
  57. return suf[i-1];
  58. }
  59. }
  60. }
  61. return -1;
  62. }
  63. int main(){
  64. int T;
  65. cin>>T;
  66. for(int cas=1; cas<=T; cas++){
  67. printf("Case #%d: ", cas);
  68. int n;
  69. cin>>n;
  70. cin>>s;
  71. int len0=strlen(s), len=len0;
  72. for(int i=1; i<n; i++){
  73. s[len++]='#';
  74. cin>>(s+len);
  75. len+=strlen(s+len);
  76. }
  77. int m=256;
  78. for(int i=0; i<=len; i++){
  79. if(s[i]=='#') a[i]=m++;
  80. else a[i]=s[i];
  81. }
  82. SA(a, len+1, m, suf, suf2, rk, cnt);
  83. calc(a, suf, len+1, rk, h);
  84. int l=0, r=len0+1, res=-1;
  85. for(; l+1<r; ){
  86. int mid=(l+r)>>1;
  87. int tmp=ok(mid, len0, len, h);
  88. if(tmp!=-1){
  89. res=tmp;
  90. r=mid;
  91. }
  92. else l=mid;
  93. }
  94. if(r>len0) puts("Impossible");
  95. else{
  96. for(int i=res; i<res+r; i++)
  97. putchar(s[i]);
  98. puts("");
  99. }
  100. }
  101. return 0;
  102. }

2016 ACM-ICPC China Finals #F Mr. Panda and Fantastic Beasts的更多相关文章

  1. UVAL 7902 2016ECfinal F - Mr. Panda and Fantastic Beasts

    题意: 给出n个串,求一个最短的第一个串的子串使它不在其他的n-1个串中出现,若有多个求字典序最小的. Limits: • 1 ≤ T ≤ 42. • 2 ≤ N ≤ 50000. • N ≤ S1 ...

  2. 2016EC Final F.Mr. Panda and Fantastic Beasts

    题目大意 \(T(1\leq T\leq42)\)组数据,给定\(n(2\leq n\leq 50000)\)个字符串\(S_{i}(n\leq\sum_{i=1}^{n}S_{i}\leq 2500 ...

  3. [acm/icpc2016ChinaFinal][CodeforcesGym101194] Mr. Panda and Fantastic Beasts

    地址:http://codeforces.com/gym/101194 题目:略 思路: 这题做法挺多的,可以sam也可以后缀数组,我用sam做的. 1.我自己yy的思路(瞎bb的) 把第一个串建立s ...

  4. Gym 101194F Mr. Panda and Fantastic Beasts

    #include<bits/stdc++.h> using namespace std; #define ms(arr,a) memset(arr,a,sizeof arr) #defin ...

  5. 2016 ACM/ICPC Asia Regional Dalian Online 1006 /HDU 5873

    Football Games Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)To ...

  6. ACM - ICPC World Finals 2013 C Surely You Congest

    原题下载:http://icpc.baylor.edu/download/worldfinals/problems/icpc2013.pdf 题目翻译: 试题来源 ACM/ICPC World Fin ...

  7. HDU 5874 Friends and Enemies 【构造】 (2016 ACM/ICPC Asia Regional Dalian Online)

    Friends and Enemies Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Othe ...

  8. HDU 5889 Barricade 【BFS+最小割 网络流】(2016 ACM/ICPC Asia Regional Qingdao Online)

    Barricade Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total S ...

  9. HDU 5875 Function 【倍增】 (2016 ACM/ICPC Asia Regional Dalian Online)

    Function Time Limit: 7000/3500 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total ...

随机推荐

  1. android布局不带参数返回

    package com.example.lesson3_4; import java.util.ArrayList; import java.util.List; import android.app ...

  2. Nodejs + Jshint自动化静态代码检查

    1.   目的 提交代码前能够自动化静态代码检查,提高代码质量 2.   准备 1.    Nodejs安装: 官方地址:http://nodejs.org/ 安装说明:根据电脑配置下载对应的版本进行 ...

  3. HTTPs与HTTP的性能

    (参考:https://blog.csdn.net/chinafire525/article/details/78911734 https://blog.csdn.net/hherima/articl ...

  4. 使用python批量导入txt导入excel表格(公司电脑设备ip和人员统计)

    #!/bin/env python # -*- encoding: utf- -*- import datetime import time import os import sys import x ...

  5. 更新Svn客户端后,右键菜单中没有TortoiseSVN

    环境: OS:                 Windows XP sp3 升级后SVNServer:    VisualSVN Server 2.7.3 升级后SVNClient:    小乌龟: ...

  6. UVA 1347 Tour 双调TSP

    TSP是NP难,但是把问题简化,到最右点之前的巡游路线只能严格向右,到最右边的点以后,返回的时候严格向左,这个问题就可以在多项式时间内求出来了. 定义状态d[i][j]表示一个人在i号点,令一个人在j ...

  7. Java IO流之字符缓冲流

    字符流: 1.加入字符缓存流,增强读取功能(readLine) 2.更高效的读取数据 BufferedReader 从字符输入流读取文本,缓冲各个字符,从而实现字符.数组和行的高效读取. FileRe ...

  8. stringstream clear与str("")的问题

    一.str与clear函数 C++Reference对于两者的解释: 可见:clear()用来设置错误状态,相当于状态的重置:str用来获取或预置内容 二.区别 运行下面测试代码: #include& ...

  9. 用例重试机制rerunfailures

    安装 rerunfailures插件 pip install pytest-rerunfailures 使用: pytest --reruns  重试次数 如:pytest --reruns  2 重 ...

  10. centos7设置sshd端口,firewall,selinux设置

    https://blog.csdn.net/qq_31927797/article/details/81095829 #停止firewallsystemctl stop firewalld.servi ...