[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 ...
随机推荐
- springMVC搭建分布式框架
https://www.cnblogs.com/lr393993507/p/7652717.html https://www.cnblogs.com/Tpf386/p/10987931.html
- Oracle数据库常见sql
-新建表:create table table_name( id varchar2(300) primary key, name varchar2(200) not null); --插入数据 ins ...
- 冰河又一MySQL力作出版(文末送书)!!
写在前面 继<海量数据处理与大数据技术实战>之后,冰河的又一力作<MySQL技术大全:开发.优化与运维实战>出版,相信这本书对任何想系统学习MySQL的小伙伴来说,都会带来实质 ...
- Idea创建Maven项目时,没有自动添加Artifacts
可能的原因是没有进行更新,因为第一次创建时由于要下载东西,所以pom文件是自动改变的,如果没有设置自动更新maven项目,就可能出现这种情况 这时候只要去maven project中点击一下更新按钮, ...
- docker获取Let's Encrypt永久免费SSL证书
一 起因 官方的cerbot太烦了,不建议使用 还不如野蛮生长的acme.sh,而这里介绍docker运行cerbot获取Let's Encrypt永久免费SSL证书 二 选型 cerbot的证书不会 ...
- 搭建 Typecho 个人博客
搭建 Typecho 个人博客 前言 最近在学习中,感觉有个自己的博客,用来记录学习总结,写写生活点滴是件不错的事. 在网上看到 Typecho 博客和 WordPress博客,顿时被 Typecho ...
- 杭电OJ:1089----1096(c++)(ACM入门第一步:所有的输入输出格式)
1089:输入输出练习的A + B(I) 问题描述 您的任务是计算a + b. 太容易了?!当然!我专门为ACM初学者设计了这个问题. 您一定已经发现某些问题与此标题具有相同的名称,是的,所有这些问题 ...
- java对象
原文链接http://zhhll.icu/2020/04/26/java%E5%9F%BA%E7%A1%80/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/java%E5% ...
- 详解线程池的作用及Java中如何使用线程池
服务端应用程序(如数据库和 Web 服务器)需要处理来自客户端的高并发.耗时较短的请求任务,所以频繁的创建处理这些请求的所需要的线程就是一个非常消耗资源的操作.常规的方法是针对一个新的请求创建一个新线 ...
- Flutter 布局类组件:层叠布局(Stack和Positioned)
前言 层叠布局,即子组件可以根据距父容器四个角的位置来确定自身的位置.绝对定位运行子组件堆叠起来,即按照代码中声明的顺序. Flutter中使用Stack和Positioned这两个组件来配合实现绝对 ...