[JZOJ6347] 【NOIP2019模拟2019.9.8】ZYB玩字符串
题目
题目大意
有一个字符串\(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玩字符串的更多相关文章
- [JZOJ6347]:ZYB玩字符串(DP+记忆化搜索)
题目描述 $ZYB$获得了一个神秘的非空字符串$p$. 初始时,串$S$是空的. $ZYB$会执行若干次这样的操作: $1.$选取$S$中的一个任意的位置(可以是最前面或者最后面) $2.$在这个位置 ...
- 6424. 【NOIP2019模拟2019.11.13】我的订书机之恋
题目描述 Description Input Output Sample Input 见下载 Sample Output 见下载 Data Constraint 题解 lj题卡线段树 求出每个右端点往 ...
- 6392. 【NOIP2019模拟2019.10.26】僵尸
题目描述 题解 吼题但题解怎么这么迷 考虑一种和题解不同的做法(理解) 先把僵尸离散化,h相同的钦(ying)点一个大小 (可以发现这样每种情况只会被算正好一次) 计算完全被占领的方案,然后1-方案/ ...
- 6389. 【NOIP2019模拟2019.10.26】小w学图论
题目描述 题解 之前做过一次 假设图建好了,设g[i]表示i->j(i<j)的个数 那么ans=∏(n-g[i]),因为连出去的必定会构成一个完全图,颜色互不相同 从n~1染色,点i的方案 ...
- 6377. 【NOIP2019模拟2019.10.05】幽曲[埋骨于弘川]
题目描述 题解 随便bb 详细题解见 https://www.cnblogs.com/coldchair/p/11624979.html https://blog.csdn.net/alan_cty/ ...
- 6364. 【NOIP2019模拟2019.9.20】养马
题目描述 题解 一种显然的水法:max(0,-(点权-边权之和*2)) 这样会挂是因为在中途体力值可能会更小,所以考虑求走完每棵子树所需的至少体力值 考虑从子树往上推求出当前点的答案 设每棵子树从根往 ...
- 6362. 【NOIP2019模拟2019.9.18】数星星
题目描述 题解 一种好想/好写/跑得比**记者还快的做法: 对所有询问排序,按照R递增的顺序来处理 维护每个点最后一次被覆盖的时间,显然当前右端点为R时的答案为所有时间≥L的点的权值之和 LCT随便覆 ...
- 6359. 【NOIP2019模拟2019.9.15】小ω的树(tree)(定期重构)
题目描述 题解 qy的毒瘤题 CSP搞这种码农题当场手撕出题人 先按照边权从大到小建重构树,然后40%暴力修改+查找即可 100%可以定期重构+平衡规划,每次把B个询问拉出来建虚树,在虚树上暴力维护每 ...
- 【NOIP2019模拟2019.11.13】旅行 && GDKOI2018 还念(二分答案+dij)
Description: 题解: 显然满足二分性. 并且每一条边要不选l要不选r. 二分的那条链肯定要选l. 考虑有两个人在走最短路,一个人一开始必须走二分的那条链,要求第一个人走的比第二个人快. 安 ...
随机推荐
- vue中:key 和react 中key={} 的作用,以及ref的特性?
vue中:key 和react 中key={} 为了给 vue 或者react 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性 一句话概括就是 ...
- beforeEach的深入研究,及beforeEach和beforeRouteEnter区别?
之前一直困惑它俩的区别,也没找到合适的文档,直到有天看到一篇博客,一起来学习下: 之前是在created钩子函数里面,发现这是在今天当前页面之后了.先回顾一下钩子函数beforeEach const ...
- usb-host与外设通信(二)
本文是接着上一篇的的usb-host与外设通信(一)接着写的 3.枚举设备 当你的程序运行时,如果应用程序对当前连接的USB设备都感兴趣的,程序可以枚举所以当前的设备.使用getDeviceList( ...
- backface-visibility:hidden
backface-visibility:hidden 不面向屏幕时隐藏
- loj2001[SDOI2017]树点染色
题意:给你一棵树,一开始每个点上的颜色互不相同.三种操作:op1:x到根的路径上的点都染上一种新的颜色.op2:设一条路径的权值为val(x,y),求x到y路径的val.op3:询问x的子树中最大的到 ...
- Redis探索之路(一):Redis简介
一:NOSQL NotOnlySQL 反SQL运动,非关系型数据库(区别于Mysql关系型书库). 随着Web2.0兴起,“高性能”,“高并发”成为主流. NoSQL以key-value形式存储数据, ...
- Download Blackarch Linux
https://www.blackarch.org/
- Java——package和import关键字
1.8 package和import关键字 1.8.1 package 包其实就是目录,特别是项目比较大,java 文件特别多的情况下,我们应该分目录管理,在java 中称为分包管理,包名称通常采用小 ...
- 云栖干货回顾 | 云原生数据库POLARDB专场“硬核”解析
POLARDB是阿里巴巴自主研发的云原生关系型数据库,目前兼容三种数据库引擎:MySQL.PostgreSQL.Oracle.POLARDB的计算能力最高可扩展至1000核以上,存储容量可达100TB ...
- QueryList采集页面链接及对应标题
<?php header('content-type:text/html;charset=utf-8'); require 'vendor/autoload.php'; use QL\Query ...