题目大意

\(T(1\leq T\leq42)\)组数据,给定\(n(2\leq n\leq 50000)\)个字符串\(S_{i}(n\leq\sum_{i=1}^{n}S_{i}\leq 250000\),所有\(T\)的\(\sum S_{i}\leq 3 \times 10^6)\)求出一个最短的字符串,其仅为第\(1\)个字符串的字串(有多个长度相同的则求其中字典序最小的)。

思路

我们考虑用一个特殊字符将所有字符串串成一个串,求出该串的\(sa[\space]\)与\(lcp[\space]\),我们考虑从第一个串范围内开始的每一个后缀\(sa[i]\),找出在后缀数组中的前一个以及后一个起点不在第一个串内的后缀\(pred[i],succ[i]\)(更远的后缀与其的\(lcp\)不会更大,所以仅需一前一后最近的两个即可),我们可以对\(lcp[\space]\)做\(rmq\)来求出\(max(lcp(sa[i],pred[i]),lcp(sa[i],succ[i]))\),如果最长公共前缀为\(n\),说明以\(i\)这个位置为起点的第一个串长为\(1\sim n\)的字串都在其他串中出现过,所以以\(i\)这个位置为起点的长为\(n+1\)的第一个串的字串就是最短的以\(i\)这个位置为起点的满足要求的串(注意判断一下这个串的合法性,可能超出第一个串的范围),我们对后缀数组从前往后遍历,不断更新答案,于是可以求出在最短的情况下字典序最小的串。

代码

  1. #include<bits/stdc++.h>
  2. #include<unordered_map>
  3. #include<unordered_set>
  4. using namespace std;
  5. typedef long long LL;
  6. typedef unsigned long long ULL;
  7. typedef pair<int, int> PII;
  8. #define all(x) x.begin(),x.end()
  9. //#define int LL
  10. //#define lc p*2+1
  11. //#define rc p*2+2
  12. #define endl '\n'
  13. #define inf 0x3f3f3f3f
  14. #define INF 0x3f3f3f3f3f3f3f3f
  15. #pragma warning(disable : 4996)
  16. #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
  17. const double eps = 1e-8;
  18. const LL MOD = 1000000007;
  19. const LL mod = 998244353;
  20. const int maxn = 500010;
  21. int T, N, cnt = 0;
  22. string SS, t;
  23. int n, k;
  24. int rk[maxn], tmp[maxn], sa[maxn], lcp[maxn], flen, pred[maxn], succ[maxn];
  25. bool compare_sa(int i, int j)
  26. {
  27. if (rk[i] != rk[j])
  28. return rk[i] < rk[j];
  29. else
  30. {
  31. int ri = i + k <= n ? rk[i + k] : -1;
  32. int rj = j + k <= n ? rk[j + k] : -1;
  33. return ri < rj;
  34. }
  35. }
  36. void construct_sa(string S, int* sa)
  37. {
  38. n = S.length();
  39. for (int i = 0; i <= n; i++)
  40. {
  41. sa[i] = i;
  42. rk[i] = i < n ? S[i] : -1;
  43. }
  44. for (k = 1; k <= n; k *= 2)
  45. {
  46. sort(sa, sa + n + 1, compare_sa);
  47. tmp[sa[0]] = 0;
  48. for (int i = 1; i <= n; i++)
  49. tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0);
  50. for (int i = 0; i <= n; i++)
  51. rk[i] = tmp[i];
  52. }
  53. }
  54. void construct_lcp(string S, int* sa, int* lcp)
  55. {
  56. int n = S.length();
  57. for (int i = 0; i <= n; i++)
  58. rk[sa[i]] = i;
  59. int h = 0;
  60. lcp[0] = 0;
  61. for (int i = 0; i < n; i++)
  62. {
  63. int j = sa[rk[i] - 1];
  64. if (h > 0)
  65. h--;
  66. for (; j + h < n && i + h < n; h++)
  67. {
  68. if (S[j + h] != S[i + h])
  69. break;
  70. }
  71. lcp[rk[i] - 1] = h;
  72. }
  73. }
  74. int ST[maxn][30];
  75. void LCP_init(int n)
  76. {
  77. for (int i = 0; i < n; i++)
  78. ST[i][0] = lcp[i];
  79. for (int j = 1; (1 << j) <= n; j++)
  80. {
  81. for (int i = 0; i + (1 << j) - 1 < n; i++)
  82. ST[i][j] = min(ST[i][j - 1], ST[i + (1 << (j - 1))][j - 1]);
  83. }
  84. }
  85. int LCP(int l, int r)//[l,r)
  86. {
  87. if (l >= r)
  88. return 0;
  89. int k = floor(log2(r - l));
  90. return min(ST[l][k], ST[r - (1 << k)][k]);
  91. }
  92. void solve()
  93. {
  94. int len = SS.length(), ans = -1, sou = -1;
  95. construct_sa(SS, sa);
  96. construct_lcp(SS, sa, lcp);
  97. LCP_init(len);
  98. int temp = 0;
  99. for (int i = 1; i <= len; i++)
  100. {
  101. if (sa[i] >= flen)
  102. temp = i;
  103. else
  104. pred[i] = temp;//前一个最近的从第一个字串外开始的后缀
  105. }
  106. temp = 0;
  107. for (int i = len; i >= 1; i--)
  108. {
  109. if (sa[i] >= flen)
  110. temp = i;
  111. else
  112. succ[i] = temp;//后一个最近的从第一个字串外开始的后缀
  113. }
  114. for (int i = 1; i <= len; i++)
  115. {
  116. int mx = 0;
  117. if (sa[i] < flen)
  118. {
  119. if (pred[i])
  120. mx = max(mx, LCP(pred[i], i));
  121. if (succ[i])
  122. mx = max(mx, LCP(i, succ[i]));
  123. if ((ans == -1 || ans > mx + 1) && sa[i] + mx + 1 <= flen)
  124. ans = mx + 1, sou = sa[i];
  125. }
  126. }
  127. if (ans == -1)
  128. cout << "Case #" << cnt << ": Impossible" << endl;
  129. else
  130. {
  131. cout << "Case #" << cnt << ": ";
  132. for (int i = sou; i < sou + ans; i++)
  133. cout << SS[i];
  134. cout << endl;
  135. }
  136. }
  137. int main()
  138. {
  139. IOS;
  140. cin >> T;
  141. while (T--)
  142. {
  143. cnt++;
  144. memset(pred, 0, sizeof(pred));
  145. memset(succ, 0, sizeof(succ));
  146. cin >> N >> SS;
  147. flen = SS.size();
  148. for (int i = 2; i <= N; i++)
  149. {
  150. cin >> t;
  151. SS += '#' + t;
  152. }
  153. solve();
  154. }
  155. return 0;
  156. }

2016EC Final 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. 2016 ACM-ICPC China Finals #F Mr. Panda and Fantastic Beasts

    题目链接$\newcommand{\LCP}{\mathrm{LCP}}\newcommand{\suf}{\mathrm{suf}}$ 题意 给定 $n$ 个字符串 $s_1, s_2, \dots ...

  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. ICPC 2016 China Final J. Mr.Panda and TubeMaster【最大费用最大流】

    有一种限制下界强制选的,但是也可以不用 把每个格点拆成两个,一个连s一个连t,对于不是必选的连中间连流量1费用0边表示不选,然后黑白染色,黑点连横着白点连竖着,边权就是这条水管的权值,然后跑最大费用最 ...

  6. 【费用流】 ICPC 2016 China Final J. Mr.Panda and TubeMaster

    表示“必须选”的模型 题目大意 题目分析 一个格子有四种方式看上去很难处理.将横竖两个方向分开考虑,会发现:因为收益只与相邻格子是否连通有关,所以可以将一个格子拆成表示横竖两个方向的,互相独立的点. ...

  7. China Final J - Mr.Panda and TubeMaster

    和一般的管道不同 不能类似“无限之环”或者“弯弯国”的建图,因为这两个题都是某些位置必须有,或者必须没有 但是本题可以有的位置随意,不能限制某个位置要么流2,要么流0,(实际上可能流了1过去) 所以建 ...

  8. 2018 China Collegiate Programming Contest Final (CCPC-Final 2018)-K - Mr. Panda and Kakin-中国剩余定理+同余定理

    2018 China Collegiate Programming Contest Final (CCPC-Final 2018)-K - Mr. Panda and Kakin-中国剩余定理+同余定 ...

  9. hdu6007 Mr. Panda and Crystal 最短路+完全背包

    /** 题目:hdu6007 Mr. Panda and Crystal 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6007 题意:魔法师有m能量,有n ...

随机推荐

  1. Tomcat-如何创建动态的web工程及目录介绍

    1,IDEA中如何创建动态web工程 (1)创建一个新模块 (2)选择你要创建什么类型的模块 (3)输入模块名,finish完成创建 创建成功如下图: 一般在WEB-INF下建一个lib目录 存放ja ...

  2. Java安全之C3P0链利用与分析

    Java安全之C3P0链利用与分析 0x00 前言 在一些比较极端情况下,C3P0链的使用还是挺频繁的. 0x01 利用方式 利用方式 在C3P0中有三种利用方式 http base JNDI HEX ...

  3. Atcoder ARC-062

    ARC062(2020.7.13) A 可以考虑直接同时扩大这次的两个票数,那么使得两数均大于之前位置的票数就是最优的,扩大的话直接除一下上取整即可. B 贪心即可. C 可以发现这个东西如果直接计数 ...

  4. Android 四种方法写按钮点击事件

    1.匿名内部类的方式 2. 创建一个类实现onclickListener,实现onclick方法,设置控件点击事件时传一个类的对象. 3. 让当前类实现onclickListener,设置控件点击事件 ...

  5. Docker的数据管理(下)——docke镜像的创建

    Docker的数据管理(下)--docke镜像的创建 1.基于现有镜像创建 2.基于本地模板创建 3.基于 dockerfile 创建 4.Dockerfile 镜像操作常用命令 5.dockerfi ...

  6. LeetCode随缘刷题之Java经典面试题将一个字符串数组进行分组输出,每组中的字符串都由相同的字符组成

    今天给大家分享一个Java经典的面试题,题目是这样的: 本题是LeetCode题库中的49题. 将一个字符串数组进行分组输出,每组中的字符串都由相同的字符组成 举个例子:输入["eat&qu ...

  7. 协程 & IO模型 & HTTP协议

    今日内容 进程池与线程池的基本使用 协程理论与实操 IO模型 前端简介 内容详细 一.进程池与线程池的基本使用 1.进程池与线程池的作用 为了保证计算机硬件安全的前提下,提升程序的运行效率 2.回调机 ...

  8. 请你说说Spring

    一. Spring是什么? 是一个轻量级的开源容器框架,用来装JavaBean,可以把其他的一些框架进行整合使用,使得开发更快,更简洁. 轻量级:占用空间小,非入侵式的(Spring中的对象不依赖于S ...

  9. 《深度探索C++对象模型》第二章 | 构造函数语意学

    默认构造函数的构建操作 默认构造函数在需要的时候被编译器合成出来.这里"在需要的时候"指的是编译器需要的时候. 带有默认构造函数的成员对象 如果一个类没有任何构造函数,但是它包含一 ...

  10. Realtime Data Processing at Facebook

    概要 这篇论文发表于2016年,主要是介绍Facebook内部的流式计算平台的设计与思考,对于流式计算的关键特性的实现选型上进行深度对比分析. 流式计算系统5个衡量指标 文中提到有5个重要的考量部分 ...