贪心,求出前$i$个字符串所能组成的字典序最小的字符串$ans$(特别的,这里的字典序有$ab>abc$),同时保证剩下的长度能通过$l_{i+1},...,l_{n}$拼接

考虑插入一个字符串$s_{i+1}$,在$ans$的任意拼接处(包括开头)可以替换上这个串,之后使得$ans$的字典序最小且长度合法,容易发现有:第一个能使$ans$字典序变小(这里指严格变小)的位置一定是使得$ans$字典序最小的位置(如果不存在就加在最后)

枚举插入的位置(所有合法断点的位置),相当于要判断插入后能否让$ans$更小,由于前半部分相同,即比较$s_{i+1}$和$ans$的一个后缀,暴力比较复杂度为$o(n^{2}k)$,无(ke)法(yi)通过

考虑二分+hash找到lcp,之后判断下一个字符即可,这样复杂度为$o(nk\log_{2}k)$(这里不是$o(n^{2}\log_{2}k)$的原因是需要计算hash值),常数比较优秀可以通过

还可以发现这是一个exkmp的模板题,时间复杂度可以做到$o(nk)$

然而这道题还有很多的细节,这里给出几组毒瘤的数据(/为回车):3 3/abd/ab/c,3 3/abc/ab/d,4 3/a/b/abd/c,3 3/a/aa/ab,4 4/a/a/aa/b,4 4/a/aa/c/ab(答案自己手算)

(不过atcoder的数据极水,这些数据全错+暴力求lcp都是可以通过的)

 1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 10005
4 int n,k,len,l[N],a[N],b[N],extend[N],f[2005][N];
5 char s[2005][N],ans[N];
6 void calc(int l1,char *s1,int l2,char *s2){
7 memset(extend,0,sizeof(extend));
8 for(int i=0;i<l1;i++)
9 while ((i+extend[i]<l1)&&(extend[i]<l2)&&(s1[i+extend[i]]==s2[extend[i]]))extend[i]++;
10 }
11 int main(){
12 scanf("%d%d",&n,&k);
13 for(int i=1;i<=n;i++){
14 scanf("%s",s[i]);
15 l[i]=strlen(s[i]);
16 }
17 f[n+1][0]=1;
18 for(int i=n;i;i--)
19 for(int j=k;j>=0;j--){
20 f[i][j]=f[i+1][j];
21 if (j>=l[i])f[i][j]|=f[i+1][j-l[i]];
22 }
23 len=a[0]=0;
24 for(int i=1;i<=n;i++){
25 calc(len,ans,l[i],s[i]);
26 b[0]=0;
27 int flag=0,lll=0,aa=0,bb=0;
28 for(int j=0,ll=0;j<=a[0];ll+=a[++j]){
29 if ((k<ll+l[i])||(!f[i+1][k-ll-l[i]])){
30 if (j<a[0])b[++b[0]]=a[j+1];
31 continue;
32 }
33 int x=extend[ll];
34 if (x==l[i]){
35 b[++b[0]]=a[j+1];
36 continue;
37 }
38 if (ll+x==len){
39 flag=1;
40 aa=j;
41 bb=b[0];
42 lll=ll;
43 if (j<a[0])b[++b[0]]=a[j+1];
44 continue;
45 }
46 if (ans[ll+x]>s[i][x]){
47 flag=0;
48 len=ll+l[i];
49 for(int p=0;p<l[i];p++)ans[ll+p]=s[i][p];
50 while ((j<a[0])&&(a[j+1]<=x)){
51 x-=a[++j];
52 l[i]-=a[j];
53 b[++b[0]]=a[j];
54 }
55 b[++b[0]]=l[i];
56 break;
57 }
58 if (j<a[0])b[++b[0]]=a[j+1];
59 }
60 if (flag){
61 int x=extend[lll],j=aa,ll=lll;
62 b[0]=bb;
63 len=ll+l[i];
64 for(int p=0;p<l[i];p++)ans[ll+p]=s[i][p];
65 while ((j<a[0])&&(a[j+1]<=x)){
66 x-=a[++j];
67 l[i]-=a[j];
68 b[++b[0]]=a[j];
69 }
70 b[++b[0]]=l[i];
71 }
72 mempcpy(a,b,sizeof(a));
73 }
74 printf("%s",ans);
75 }

最新文章

  1. HIS-DELPHI-读取数据库配置
  2. javascript函数的定义与执行
  3. Linux中下载、解压、安装文件
  4. fopen的第一个参数不能有&#39;\n&#39;
  5. opensuse-13.1体验
  6. 《统计推断(Statistical Inference)》读书笔记——第1章 概率论
  7. repo: 创建local manifest以及如何添加app到CM/Android build系统中
  8. RabbitMQ 一二事(4) - 路由模式介绍
  9. PHP读取一个目录下的文件个数
  10. freemarker实例2
  11. Promise 学习笔记
  12. 解密 Uber 数据团队的基础数据架构优化之路
  13. windows mobile仿真器内存调整
  14. 【Android 界面效果36】Fragment管理
  15. eclipse快捷键补充
  16. 修改ckeditor/ckfinder上传文件文件夹 路径以日期格式命名
  17. iOS用AFN上传图片到java后台
  18. MPSOC之7——开发流程uramdisk
  19. window 下生成NodeJs(v8.9.3) 的 VS2015 解决方案node.sln
  20. 71.纯 CSS 创作一个跳 8 字型舞的 loader

热门文章

  1. 小甲鱼零基础学python第25讲课后习题动手练习--通讯录
  2. WinForm RichTextBox 常用操作
  3. scala基础篇 使用getter和setter方法而不使用public的情形
  4. 小白自制Linux开发板 六. SPI TFT屏幕修改与移植
  5. WPF实现雷达图(仿英雄联盟)
  6. 51.N皇后问题
  7. SpringCloud 2020.0.4 系列之 Feign
  8. seata整合nacos完成分布式的部署
  9. Linux入门所必备的Linux命令和C语言基础
  10. SVN查看项目修改记录及修改内容