题面

一个长度为 \(k\) 字符串序列 \(s\) 是好的,当且仅当 \(\forall 1\le i<k\),有 \(B_i\) 既是 \(B_{i+1}\) 的前缀,又是 \(B_{i+1}\) 的后缀 .

给一个字符串序列 \(A\),求其最长好子序列 .


数据范围:\(\displaystyle \sum_k |A_k|\le 2\times 10^6\)

时限 \(2\ \rm s\),空限 \(512\rm\ MB\) .

题解

算法 1

考虑 dp .

令 \(dp_i\) 表示以 \(A_i\) 结尾的最长好序列,于是可以暴力转移 .

时间复杂度 \(O(n^3)\),期望 \(20\sim 40pts\) .

算法 2

考虑加速算法 \(1\) 中转移过程 .

字符串 Hash 处理每个子串的 border,同时构建映射 \(\mathrm M:\,border\to dp\) .

一轮 dp 可以线性完成,映射可以考虑两种实现方式

方式编号 表现 \(1\) 表现 \(2\) 时间复杂度
\(1\) std::map 平衡树 \(O(n\log n)\)
\(2\) std::unordered_map Hash Table \(O(n)\)

期望 \(100pts\) .

算法 3(标答)

记 \(\overline s\) 为 \(s\) 逆序排成的字符串 .

于是 \(s\) 是 \(t\) 的后缀等价于 \(\overline s\) 是 \(\overline t\) 的前缀 .

现在我们有两个前缀关系,建 Trie 树并且在 Trie 树上 dp 即可 .

期望 \(100pts\) .

代码

算法 1

20pts(by jijidawang)

  1. using namespace std;
  2. typedef long long ll;
  3. const int N = 1e6 + 500;
  4. int n;
  5. ll p, dp[N];
  6. string s[N];
  7. inline bool pure_chk(string a, string b)
  8. {
  9. int la = a.length(), lb = b.length();
  10. if (la > lb) return false;
  11. for (int i=0; i<la; i++)
  12. if (a[i] != b[i]) return false;
  13. return true;
  14. }
  15. inline bool chk(string a, string b)
  16. {
  17. bool ans = pure_chk(a, b);
  18. reverse(b.begin(), b.end());
  19. return ans & pure_chk(a, b);
  20. }
  21. int main()
  22. {
  23. scanf("%d", &n);
  24. for (int i=1; i<=n; i++) cin >> s[i];
  25. dp[1] = 1;
  26. for (int i=2; i<=n; i++)
  27. for (int j=1; j<i; j++)
  28. if (chk(s[j], s[i])) dp[i] = max(dp[i], dp[j]+1);
  29. ll ans = 0;
  30. for (int i=1; i<=n; i++) ans = max(ans, dp[i]);
  31. printf("%lld\n", ans);
  32. return 0;
  33. }

40pts(by Rolling_Star)

  1. using namespace std;
  2. int n,dp[2000001];
  3. string s[2000001];
  4. bool flag;
  5. inline bool check(int x,int y);
  6. int main()
  7. {
  8. cin>>n;
  9. for(register int i=1;i<=n;i++)
  10. cin>>s[i];
  11. int ans=0;
  12. dp[1]=1;
  13. for(register int i=2;i<=n;++i)
  14. {
  15. dp[i]=1;
  16. for(register int j=1;j<=i-1;++j)
  17. if(s[i].size()>=s[j].size())
  18. if(check(i,j))
  19. dp[i]=max(dp[i],dp[j]+1);
  20. ans=max(ans,dp[i]);
  21. }
  22. cout<<ans;
  23. }
  24. inline bool check(int x,int y)
  25. {
  26. for(register int i=0;i<s[y].size();++i)
  27. if(s[y][i]!=s[x][i])
  28. return false;
  29. for(register int i=s[x].size()-s[y].size(),j=0;j<s[y].size();++i,++j)
  30. if(s[y][j]!=s[x][i])
  31. return false;
  32. return true;
  33. }

算法 2

  1. using namespace std;
  2. const int N = 1e6 + 500;
  3. typedef long long ll;
  4. typedef char str[N];
  5. const ll P = 1e9+7, base = 131;
  6. int n;
  7. ll pb[N];
  8. str s;
  9. map<ll, int> dp;
  10. int main()
  11. {
  12. scanf("%d", &n);
  13. pb[0] = 1;
  14. for (int i=1; i<N; i++) pb[i] = pb[i-1] * base % P;
  15. int ans = 0;
  16. for (int i=1; i<=n; i++)
  17. {
  18. scanf("%s", s+1); int l = strlen(s+1);
  19. ll p=0, ss=0; int H=0;
  20. for (int j=1; j<=l; j++)
  21. {
  22. p = (p*base % P + s[j]) % P;
  23. ss = (ss + s[l-j+1]*pb[j-1] % P) % P;
  24. if (p == ss) H = max(H, dp[p]);
  25. }
  26. dp[p] = max(dp[p], H+1);
  27. ans = max(ans, dp[p]);
  28. } printf("%d\n", ans);
  29. return 0;
  30. }

算法 3

Pref 社论的更多相关文章

  1. @ConfigurationProperties(pref="")加载局部配置文件

    刚开始@ConfigurationProperties(文件名)直接在参数里加文件名,其实是配置前缀pref="前缀".加载局部配置文件是@PropertySource(value ...

  2. Chrome Switchs & Chrome Pref

    Chrome Switchs: https://chromium.googlesource.com/chromium/src/+/master/chrome/common/chrome_switche ...

  3. 丽泽普及2022交流赛day20 1/4社论

    目录 T1 正方形 T2 玩蛇 T3 嗷呜 T4 开车 T1 正方形 略 T2 玩蛇 略 T3 嗷呜 (插一个删一个?) 找出相同的,丢掉循环节 . 感觉非常离谱,,, 正确性存疑 正确性问 SoyT ...

  4. Minimax 社论

    目录 题面 题解 代码 Reference 题面 LOJ #2537 / 洛谷 P5298 「PKUWC2018」Minimax 一棵有根二叉树 \(\mathcal T\) . 定义结点 \(x\) ...

  5. 丽泽普及2022交流赛day22 无社论

    开始掉分模式 . T3 有人上费用流了???(id) 不用 TOC 了 . T1 暴力 T2 没看见 任意两圆不相交,gg 包含关系容易维护,特判相切 . 单调栈即可 T3 贪心 T4 神秘题

  6. 丽泽普及2022交流赛day21 社论

    A 暴力 . greater<double> -> greater<int> \(100\) -> \(50\) 代码丢了 . B dp . 考场上代码抢救一下就过 ...

  7. 丽泽普及2022交流赛day19 半社论

    目录 No Problem Str Not TSP 题面 题解 代码 Game 题面 题解 代码 No Problem 暴力 Str 存在循环节,大力找出来即可,长度显然不超过 \(10^3\) . ...

  8. 丽泽普及2022交流赛day18 社论

    A 暴力扫一遍 B 算法 0 似乎是二分 算法 1 随便贪心 C 算法 1 枚举一个点作为最大值 / 最小值,用单调栈维护其作为答案的左右端点即可轻易计算 . 时间复杂度 \(O(n)\) . 算法 ...

  9. 膜 社论(egg drop)

    题面 \(n\) 楼 \(m\) 个鸡蛋,从 \(k\) 楼及以上扔下去会碎,不能再测试 . 问至少需要扔几次确定 \(k\) . \(n\le 10^{18}\),\(m\le 64\) . 题解 ...

随机推荐

  1. NLP教程(6) - 神经机器翻译、seq2seq与注意力机制

    作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/36 本文地址:http://www.showmeai.tech/article-det ...

  2. js--promise、async 和 await 相关知识总结

    前言 promise 是前端开发人员必须掌握的知识点,本文来总结一下相关学习笔记. 正文 1.什么是prommise,promise 解决了什么问题 a.promise 是什么 Promise 是承诺 ...

  3. ElasticSearch7.3学习(二十五)----Doc value、query phase、fetch phase解析

    1.Doc value 搜索的时候,要依靠倒排索引: 排序的时候,需要依靠正排索引,看到每个document的每个field,然后进行排序. 所谓的正排索引,其实就是doc values. 在建立索引 ...

  4. 我的总结常用的js知识

    nvm nvm是node的包管理工具.在不同的项目下使用不同的node版本.下载地址 https://github.com/coreybutler/nvm-windows/releasesnvm in ...

  5. node包的降版本

    1.安装版本更高的node包直接到官网去安装. 2.从版本高的node包,降低到版本低的node包. 要先卸载现在的node包,在菜单栏中可以删除. 然后通过https://nodejs.org/zh ...

  6. 『忘了再学』Shell基础 — 19、使用declare命令声明变量类型

    目录 1.declare命令介绍 2.声明数组变量类型 3.声明变量为环境变量 4.声明只读属性 5.补充: 1.declare命令介绍 Shell中所有变量的默认类型是字符串类型,如果你需要进行特殊 ...

  7. js算法-埃筛法

  8. mybatis if判断等于某个字符串

    这种写法是错误的:在OGNL的表达式中,'true'会被解析成字符,因为java是强类型的 <if test="flag=='true' "> AND ho.id = ...

  9. Linux Cgroup v1(中文翻译)(4):Block IO Controller

    Block IO Controller 1 概览 cgroup子系统blkio实现了block io控制器.无论是对存储结构上的叶子节点和还是中间节点,它对各种IO控制策略(proportional ...

  10. 万字剖析Ribbon核心组件以及运行原理

    大家好,本文我将继续来剖析SpringCloud中负载均衡组件Ribbon的源码.本来我是打算接着OpenFeign动态代理生成文章直接讲Feign是如何整合Ribbon的,但是文章写了一半发现,如果 ...