题目

题目大意

有一个字符串\(p\)。一开始字符串\(s\)为空串。

接下来进行若干次操作:在\(s\)的某个空隙中插入\(p\)。

给出操作后的\(s\),问长度最小的\(p\)。


思考历程

感觉是一道神仙题。

于是考虑暴力。

在\(s\)前面找连续的最长串,作为\(p\)的前缀。显然这个串中只出现过一次\(s_1\)

同样地,在后面也找一条,作为后缀。

将前缀出现的位置和后缀出现的位置标记一下。

统计每个字符出现的个数,求最大公因数\(g\),表明操作的次数为\(g\)的因数。

然后按照长度从小到大枚举子串,如果当前子串的头和尾都被标记了,并且中间的字符个数的比例和整个字符串的比例相等,就取这个字符串作为\(p\)暴力判断。

暴力判断的时候,每次用\(KMP\)找出一个子串,将它删去,递归。

如果有多个这样的子串,那就分别搞。

然而出现了某细节错误,导致只有\(10\)分。


正解

这题的正解居然是\(DP\)!

考虑一个字符串,它的所有元素会在后面的操作中逐渐分离,但是它们的相对顺序是不变的。

而且它原来相邻的两个元素在后面的操作之后,两个元素之间的空间可以转化成个子问题。如果可行,则这个子问题也必定可行。

先考虑普通的\(DP\)思路:\(f_{l,r,k}\)表示区间\([l,r]\)中,有零散的\(k\)个字母拼起来等于\(p_{1..k}\),其它的都合法,是否可行。

转移有两种:一种是从\(f_{l,r-1,k-1}\)转移过来,条件是\(s[j]=p[k]\),就是加上一个零散的元素。

另一种是从\(f_{l,j,k} \ and \ f_{j,r,0}\),就是在后面拼一个合法的。

然而这样会\(TLE\)。

紧接着我们发现,实际上,\(k=(r-l+1)\mod len\)

所以就可以省去一维,然后就可以\(AC\)了。


代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>
#define N 210
inline int gcd(int a,int b){
while (b){
int k=a%b;
a=b;
b=k;
}
return a;
}
int n,nt;
char s[N],t[N],s2[N][N];
int buc[255],b2[255];
int m;
char c[255];
bool beg[N],end[N];
int p[N];
bool f[N][N];
inline bool work(int k,int len){
nt=len;
for (int i=1;i<=nt;++i)
t[i]=s[k+i-1];
memset(f,0,sizeof f);
for (int i=n;i>=1;--i){
f[i][i]=(s[i]==t[1]);
for (int j=i+1;j<=n;++j){
f[i][j]|=(f[i][j-1]&&s[j]==t[(j-1-i+1)%nt+1]);
for (int k=i+(j-i)%nt;k<j && !f[i][j];k+=nt)
f[i][j]|=(f[i][k]&&f[k+1][j]);
}
}
return f[1][n];
}
int main(){
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
int T;
scanf("%d",&T);
while (T--){
scanf("%s",s+1);
n=strlen(s+1);
memset(buc,0,sizeof buc);
for (int i=1;i<=n;++i)
buc[s[i]]++;
m=0;
for (char ch=' '+1;ch<='~';++ch)
if (buc[ch])
c[++m]=ch;
int g=n;
for (int i=1;i<=m;++i)
g=gcd(g,buc[c[i]]);
int l=1,r=n;
while (l<n && s[l+1]!=s[1])
++l;
while (r>1 && s[r-1]!=s[n])
--r;
memset(beg,0,sizeof beg);
memset(end,0,sizeof end);
for (int i=1,j;i+l-1<=n;++i){
for (j=1;j<=l;++j)
if (s[i+j-1]!=s[j])
break;
if (j<=l)
continue;
beg[i]=1;
}
for (int i=n,j;i+r-n>=1;--i){
for (j=n;j>=r;--j)
if (s[i+j-n]!=s[j])
break;
if (j>=r)
continue;
end[i]=1;
}
for (int len=max(l,n-r+1);len<=n;++len)
if (n%len==0 && g%(n/len)==0){
int t=n/len,hg=0;
memset(b2,0,sizeof b2);
for (int i=1;i<=len;++i)
b2[s[i]]++;
for (int i=1;i<=m;++i)
if (b2[c[i]]*t==buc[c[i]])
hg++;
int i;
for (i=1;i+len-1<=n;++i){
if (beg[i] && end[i+len-1] && hg==m){
if (work(i,len)){
for (int j=i;j<i+len;++j)
putchar(s[j]);
putchar('\n');
break;
}
}
if (b2[s[i]]*t==buc[s[i]])
hg--;
b2[s[i]]--;
if (b2[s[i]]*t==buc[s[i]])
hg++;
if (b2[s[i+len]]*t==buc[s[i+len]])
hg--;
b2[s[i+len]]++;
if (b2[s[i+len]]*t==buc[s[i+len]])
hg++;
}
if (i+len-1<=n)
break;
}
}
return 0;
}

总结

这都想不出来……我真是太菜了……

[JZOJ6347] 【NOIP2019模拟2019.9.8】ZYB玩字符串的更多相关文章

  1. [JZOJ6347]:ZYB玩字符串(DP+记忆化搜索)

    题目描述 $ZYB$获得了一个神秘的非空字符串$p$. 初始时,串$S$是空的. $ZYB$会执行若干次这样的操作: $1.$选取$S$中的一个任意的位置(可以是最前面或者最后面) $2.$在这个位置 ...

  2. 6424. 【NOIP2019模拟2019.11.13】我的订书机之恋

    题目描述 Description Input Output Sample Input 见下载 Sample Output 见下载 Data Constraint 题解 lj题卡线段树 求出每个右端点往 ...

  3. 6392. 【NOIP2019模拟2019.10.26】僵尸

    题目描述 题解 吼题但题解怎么这么迷 考虑一种和题解不同的做法(理解) 先把僵尸离散化,h相同的钦(ying)点一个大小 (可以发现这样每种情况只会被算正好一次) 计算完全被占领的方案,然后1-方案/ ...

  4. 6389. 【NOIP2019模拟2019.10.26】小w学图论

    题目描述 题解 之前做过一次 假设图建好了,设g[i]表示i->j(i<j)的个数 那么ans=∏(n-g[i]),因为连出去的必定会构成一个完全图,颜色互不相同 从n~1染色,点i的方案 ...

  5. 6377. 【NOIP2019模拟2019.10.05】幽曲[埋骨于弘川]

    题目描述 题解 随便bb 详细题解见 https://www.cnblogs.com/coldchair/p/11624979.html https://blog.csdn.net/alan_cty/ ...

  6. 6364. 【NOIP2019模拟2019.9.20】养马

    题目描述 题解 一种显然的水法:max(0,-(点权-边权之和*2)) 这样会挂是因为在中途体力值可能会更小,所以考虑求走完每棵子树所需的至少体力值 考虑从子树往上推求出当前点的答案 设每棵子树从根往 ...

  7. 6362. 【NOIP2019模拟2019.9.18】数星星

    题目描述 题解 一种好想/好写/跑得比**记者还快的做法: 对所有询问排序,按照R递增的顺序来处理 维护每个点最后一次被覆盖的时间,显然当前右端点为R时的答案为所有时间≥L的点的权值之和 LCT随便覆 ...

  8. 6359. 【NOIP2019模拟2019.9.15】小ω的树(tree)(定期重构)

    题目描述 题解 qy的毒瘤题 CSP搞这种码农题当场手撕出题人 先按照边权从大到小建重构树,然后40%暴力修改+查找即可 100%可以定期重构+平衡规划,每次把B个询问拉出来建虚树,在虚树上暴力维护每 ...

  9. 【NOIP2019模拟2019.11.13】旅行 && GDKOI2018 还念(二分答案+dij)

    Description: 题解: 显然满足二分性. 并且每一条边要不选l要不选r. 二分的那条链肯定要选l. 考虑有两个人在走最短路,一个人一开始必须走二分的那条链,要求第一个人走的比第二个人快. 安 ...

随机推荐

  1. javascript 学习犯错记录

    看w3c学习js,有时按自己想法来,会出一些莫名奇妙的错误,而这些问题百度到了,但因为学习原因基础不捞,导致看到了答案,却认为这不是答案 1.一个很简单的 一个html,一个js文件 我想在js中的b ...

  2. 十分钟学习 react配套的类型检测库——prop-types的运用

    js 有时在定义变量的类型为number 或string 时并不会报错,所以prop-types 是专门用来检测react ,以前的版本是把它放到react架构里面 ,现在作为一个独立的库搬出来了,跟 ...

  3. unicode_stop - 撤销控制台unicode模式(例如, 回到8-bit模式).

    总览 unicode_stop 描述 unicode_stop 撤销以前 unicode_start(1) 命令的效果, 将显示屏和键盘设回到 8-bit 模式.

  4. C语言 常量

    常量的定义:在运行过程中,其值不能改变的量称为常量. 常量的分类 整型常量  实型常量  字符常量 demo #include <stdio.h> void main() { printf ...

  5. Java笔记目录

    目录 一.Java语言概述... 1 1.计算机语言发展史... 1 1.1计算机语言的发展... 1 1.2人与计算机做交互... 1 1.3计算机语言... 1 1.4软件... 1 2.Java ...

  6. jQuery-介绍 加载 选择器 样式操作 属性操作 绑定click事件

    jQuery - 介绍 加载 选择器 样式操作 属性操作 绑定click事件 注意:以下部分问题不能实现效果,因该是单词拼写错误(少个t)或者没有加引号(“swing”)... jquery介绍 jQ ...

  7. Java--会移动、反弹的球

    package firstpack; import java.awt.*; public class MyStar { public static void main(String[] args) { ...

  8. 数据结构C++版-栈

    一.概念 二.应用实例 1.进制转换 #include <stdlib.h> #include <iostream> #include <string> #incl ...

  9. VS2010-MFC(Ribbon界面开发:为Ribbon Bar添加控件)

    转自:http://www.jizhuomi.com/software/253.html 前面一节为大家简单介绍了如何创建Ribbon样式的应用程序框架,本节教程就来初步讲讲怎样为Ribbon Bar ...

  10. springmvc静态资源;mvc:default-servlet-handler后Controller失效

    springmvc静态资源;mvc:default-servlet-handler后Controller失效 web.xml配置<url-pattern>/</url-pattern ...