[JSOI2019]节日庆典 做题心得
[JSOI2019]节日庆典 做题心得
一个性质有趣的字符串题
这要是在考场上我肯定做不出来吧
一开始还以为要 SAM 什么的暴力搞,没想到只用到了 \(Z\) 函数 —— 也是我生疏了罢
(学了啥忘了啥,这可怎么去wc啊啊啊
思路
考虑维护候选集合 \(S\),表示这个位置 可能 是最优位置。
假设我们可以知道 \(S\),拿 \(Z\) 函数求一下 \(LCP\) 就可以知道是不是最优的了。
大胆猜测一个性质,要么可以快速的找 \(S\) 中最小的位置,要么 \(S\) 的大小不会很大,可以暴力找。
第一个思路不太好搞,那看来就选第二个思路吧
假设现在考虑前 \(k\) 位
首先可以来一个优化:如果还没循环,就比出来了胜负,那么大的那个一定不会是最优解 —— 并且随着 \(k\) 的增加,显然不会翻身成更优的
那现在对于 \(i,j\in S,i<j\),一定有 \(LCP(s[i:k],s[j:k])= k-j+1\)。
考虑两个 \(i,j\) ,如果 \([i,i+LCP-1]\) 和 \([j,j+LCP-1]\) 不重合,看来没什么性质
如果重合,似乎有些有趣的性质,先放结论:
如果重合,即 \(k-j+1>j-i\),则 \(j\) 一定不会是最优的

我相信这个图还挺清楚的
红色是 \(i,j\) 的 \(LCP\)。然后设 \(i\) 到 \(j\) 前面是 \(A=s[i:j-1]\),然后红色减去 \(A\) 之后剩下的是 \(B=s[j:i+LCP-1]\),是从 \(j\) 开始的。由于两个红色相等,所以 \(B\) 是红色的前缀,对应到后面,它也是红色的后缀(即它是红色的 border)
\(p\) 是 \(j\) 往后数一个 \(A\) 之后的开始位置
设 \(i\) 前面的是 \(C\)。\(i\) 开始的循环串就是 \(AABC\),\(j,p\) 同理
然后发现 \(BC\) 作为一个整体出现,把它看成 \(D\)。然后就清楚多了:
如果 \(D<A\),那么 \(p\) 开始是最小的;
如果 \(A<D\),那么 \(i\) 开始是最小的;
如果 \(A=D\),那么三个一样大;
总之,忽略 \(j\) ,对最大值没有影响
那么 \(S\) 集合中,每往前数一个数,它到上一个的距离,都比上一个到 \(k\) 的距离大。和启发式合并类似的,有一个基本事实:
一个数加上比它大的数,至少翻一倍
那 \(S\) 集合中数到 \(k\) 的距离,每次至少翻一倍,所以 \(S\) 的大小是 \(\log\) 的。
每次新加入元素的时候维护一下即可,然后分段考虑一下,求最小的那个开始位置。
#include <bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
#define N 10000007
#define F(i,l,r) for(int i=l;i<=r;++i)
#define D(i,r,l) for(int i=r;i>=l;--i)
#define Fs(i,l,r,c) for(int i=l;i<=r;c)
#define Ds(i,r,l,c) for(int i=r;i>=l;c)
#define MEM(x,a) memset(x,a,sizeof(x))
#define FK(x) MEM(x,0)
#define Tra(i,u) for(int i=G.st(u),v=G.to(i);~i;i=G.nx(i),v=G.to(i))
#define p_b push_back
#define sz(a) ((int)a.size())
#define all(a) a.begin(),a.end()
#define iter(a,p) (a.begin()+p)
int n;
char s[N];
void Input()
{
scanf("%s",s+1);
n=strlen(s+1);
}
int z[N];
void Z_Function()
{
z[1]=n; F(i,2,n) z[i]=0;
int l=0,r=0;
F(i,2,n)
{
if (i<=r) z[i]=min(z[i-l+1],r-i+1);
while(i+z[i]<=n and s[i+z[i]]==s[z[i]+1]) ++z[i];
if (i+z[i]-1>=r) l=i,r=i+z[i]-1;
}
}
int c[N],cp=0;
int stk[N],top=0;
void fuckoff(int k)
{
while(top) stk[top--]=0;
F(i,1,cp)
{
int x=c[i];
while(top and s[stk[top]+k-x]>s[k])
{
--top;
}
if (top and s[stk[top]+k-x]<s[k]) continue;
stk[++top]=x;
}
F(i,1,cp) c[i]=0; cp=top; F(i,1,top) c[i]=stk[i];
while(top) stk[top--]=0;
D(i,cp,1)
{
while(top and k-stk[top]+1>stk[top]-c[i]) --top;
stk[++top]=c[i];
}
F(i,1,cp) c[i]=0; cp=top; F(i,1,top) c[i]=stk[top-i+1];
}
int getmin(int k)
{
int ansp=c[1];
F(i,2,cp)
{
int x=c[i];
// printf("x=%d cur=%d\n",x,ansp);
int LCP1=k-x+1;
int LCP2=min(z[ansp+LCP1],k-(ansp+LCP1)+1);
// printf(" LCP2=%d\n",LCP2);
if (LCP2<k-(ansp+LCP1)+1)
{
int p1=ansp+LCP1+LCP2;
int p2=LCP2+1;
// printf(" case2 p1=%d p2=%d\n",p1,p2);
if (p2>k) continue;
if (s[p1]>s[p2])
{
// puts(" better");
ansp=x;
}
}
else
{
int LCP3=min(z[LCP2+1],k-LCP2);
int p1=LCP3+1;
int p2=LCP2+LCP3+1;
// printf(" LCP3=%d\n",LCP3);
// printf(" case3 p1=%d p2=%d\n",p1,p2);
if (p2>k) continue;
if (s[p1]>s[p2])
{
// puts(" better");
ansp=x;
}
}
}
return ansp;
}
void Sakuya()
{
Z_Function();
F(i,1,n)
{
c[++cp]=i;
fuckoff(i);
printf("%d ",getmin(i));
}
puts("");
}
void IsMyWife()
{
Input();
Sakuya();
}
}
#undef int //long long
int main()
{
Flandre_Scarlet::IsMyWife();
getchar();
return 0;
}
[JSOI2019]节日庆典 做题心得的更多相关文章
- [BJOI2016]水晶 做题心得
[BJOI2016]水晶 做题心得 这是一个写了我两小时的傻逼题.写这个题浪费了一堆时间后,我才意识到我码力又不行了.于是整理起了实现技巧,开始练码力. 思路 不难.首先把 \((x,y,z)\) 变 ...
- CF1416D 做题心得
CF1416D 做题心得 上次在某trick中提到了这个题,一开始觉得太毒瘤没有写,现在把它补上了. 感觉实现这个东西,比单纯收获一个trick,收获的东西多太多了. 主要思路 它的主要trick是& ...
- [NOIP补坑计划]NOIP2017 题解&做题心得
终于做完了…… 场上预计得分:?(省一分数线:295) 由于看过部分题解所以没有预计得分qwq 题解: D1T1 小凯的疑惑 题面 震惊!一道小学奥数题竟难倒无数高中考生! 欢迎大家以各种姿势*和谐* ...
- [NOIP补坑计划]NOIP2016 题解&做题心得
感觉16年好难啊QAQ,两天的T2T3是不是都放反了啊…… 场上预计得分:100+80+100+100+65+100=545(省一分数线280) ps:loj没有部分分,部分分见洛咕 题解: D1T1 ...
- [NOIP补坑计划]NOIP2015 题解&做题心得
感觉从15年开始noip就变难了?(虽然自己都做出来了……) 场上预计得分:100+100+60~100+100+100+100=560~600(省一分数线365) 题解: D1T1 神奇的幻方 题面 ...
- [NOIP补坑计划]NOIP2013 题解&做题心得
场上预计得分:100+100+100+100+100+60=560(省一分数线410) 五道傻逼题+一道大搜索题…… 题解: D1T1 转圈游戏 题面 水题送温暖~ #include<algor ...
- [NOIP补坑计划]NOIP2012 题解&做题心得
场上预计得分:100+90+70+100+100+3060=490520(省一分数线245) 题解: D1T1 Vigenère 密码 题面 水题送温暖~~ #include<iostream& ...
- [NOIP补坑计划]NOIP2014 题解&做题心得
六道普及组题,没啥好说的 场上预计得分:100+100+100+100+100+100=600(省一分数线490) (AK是不可能AK的,这辈子不可能AK的) 题解: D1T1 生活大爆炸版石头剪刀布 ...
- [JSOI2019]节日庆典(Z-algorithm)
要想让一个位置作为最小循环,其必须是最小后缀,然后一个字符串的最小后缀不超过O(logn)个,于是维护备选集合即可. 然而要在O(n)复杂度求解,需要求出原串后缀与原串的LCP长度,需要用Z-algo ...
随机推荐
- 使用iconv进行文件编码转换
在使用科大讯飞的时候输出字符是gbk字符编码.但是在ubuntu下gbk显示乱码,故用iconv进行字符编码转换.下面是我整理的字符编码转化的程序案例.从gbk2312转换到utf-8. 程序代码: ...
- niceyoo的2020年终总结-2021年Flag
碎碎念,向本命年说再见! 又到了一年一度立 Flag 的时间了,怎么样,去年的 Flag 大家实现的怎么样?还有信心立下 2021 年的 Flag 吗~ 今年我算比较背的,年初的一次小意外,直接在床上 ...
- jQuery EasyUI学习一
1. jQuery EasyUI介绍 1. 创建组件的方式和原理(掌握) 2. 组件三要素(掌握) 3. Panel.LinkButton.上下文菜单;(掌握) 简介 2.1. jQuer ...
- Netty tcnative boringssl windows 32-bit 编译
1 问题 在使用Netty SSL时,我们往往会采用netty-tcnative-boringssl组件.但是netty-tcnative-boringssl在Windows上仅有64位版本的,没有3 ...
- 11. const 修饰成员函数
const 限定只读,对函数的实参进行保护 常数据成员:必须出现在类的定义体中,常数据成员必须进行初始化,并且不能被更新,但常数据成员的初始化只能通过构造函数的初始化列表进行 1. 常函数 成员函数加 ...
- htaccess在线生成工具用法大全 (转)
对于一个不懂程序的SEOER来做,更改代码方面是一件非常苦难的事情,当我们遇到301转向以及404页面的制作问题时,经常会困恼我们,这里我提供一个htaccess在线生成工具,这里有404页面链接生成 ...
- Label_table
<table border(边框) = "" width = height = align = bordercolor(边框色) = cellspacing 表格边框与单元格 ...
- 了解一下ajax
AJAX:是一种无需重新加载页面的情况下能够更新部分(局部更新)网页的技术. 1. 概念:ASychronous JavaScript And XML 异步的JavaScript和XML 首先了解一下 ...
- python学习笔记 | PyCharm出现卡顿解决方法
问题:使用pycharm时常出现 the IDE is running low on memory 的问题 表示pycharm这款IDE使用内存不足 需要在系统内存充足的情况下扩充IDE memory ...
- 配置 Docker 镜像加速源地址
docker 安装官方文档 根据实例的操作系统类型,参考相应的文档进行安装. 查看 linux 是 CentOS 还是 Ubuntu uname -a #查看系统信息 lsb_release -a # ...