题目链接

题意分析

给你一个字符串 让你求\(1-n\)长度下的字符串的中字典序最小并且最靠左的字符串的开头位置

我们考虑先建出\(SA\)

然后考虑对于一个字符串后缀排序之后

baba后缀排序之后 先不管位置 只关心字典序数字代表当前更新长度a 1
aba 2 3
ba
baba 4

我们可以发现 第二个后缀还可以更新长度为\(1\)的子串

所以我们考虑使用二分 求刚好可以满足的位置

然后我们再使用\(RMQ\)求这些位置中对应原串位置最靠左的位置

然后更新即可

CODE:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<deque>
#include<vector>
#include<ctime>
#define ll long long
#define inf 0x7fffffff
#define N 500008
#define IL inline
#define M 608611
#define D double
#define ull unsigned long long
#define R register
using namespace std;
template<typename T>IL void read(T &_)
{T __=0,___=1;char ____=getchar();while(!isdigit(____)) {if(____=='-') ___=0;____=getchar();}while(isdigit(____)) {__=(__<<1)+(__<<3)+____-'0';____=getchar();}_=___ ? __:-__;
}
/*-------------OI使我快乐-------------*/
char s[M];
int n,key,have;int num[M],res[M],ans[M];
int ST[M][20][2],lg[M];
int SA[M],rnk[M],cdy[M],wzy[M],vis[M],hei[M];
IL void Rsort()
{for(R int i=0;i<=key;++i) vis[i]=0;for(R int i=1;i<=n;++i) vis[cdy[i]]++;for(R int i=1;i<=key;++i) vis[i]+=vis[i-1];for(R int i=n;i;--i) SA[vis[cdy[wzy[i]]]--]=wzy[i];
}
IL void get_SA()
{for(R int i=1;i<=n;++i) cdy[i]=num[i],wzy[i]=i;Rsort();for(R int x=1;x<=n;x<<=1){int cnt=0;for(R int i=n-x+1;i<=n;++i) wzy[++cnt]=i;for(R int i=1;i<=n;++i) if(SA[i]>x) wzy[++cnt]=SA[i]-x;Rsort();swap(cdy,wzy);cdy[SA[cnt=1]]=1;for(R int i=2;i<=n;++i)cdy[SA[i]]=(wzy[SA[i]]==wzy[SA[i-1]]&&wzy[SA[i]+x]==wzy[SA[i-1]+x] ? cnt:++cnt);if(cnt==n) break;else key=cnt;}
}
IL void get_hei()
{for(R int i=1;i<=n;++i) rnk[SA[i]]=i;int lat,k=0;for(R int i=1;i<=n;++i){if(k) --k;lat=SA[rnk[i]-1];while(num[lat+k]==num[i+k]) ++k;hei[rnk[i]]=k;}
}
IL void pre()
{for(R int i=1;(1<<i)<=300000;++i) lg[1<<i]=i;for(R int i=2;i<=300000;++i) if(!lg[i]) lg[i]=lg[i-1];for(R int i=1;i<=n;++i) ST[i][0][0]=hei[i];for(R int j=1;(1<<j)<=n;++j)for(R int i=1;i<=n;++i)ST[i][j][0]=min(ST[i][j-1][0],ST[i+(1<<(j-1))][j-1][0]);for(R int i=1;i<=n;++i) ST[i][0][1]=SA[i];for(R int j=1;(1<<j)<=n;++j)for(R int i=1;i<=n;++i)ST[i][j][1]=min(ST[i][j-1][1],ST[i+(1<<(j-1))][j-1][1]);
}
IL int qury_hei(int le,int ri)
{if(le>ri) swap(le,ri);++le;int lx=lg[ri-le+1];return min(ST[le][lx][0],ST[ri-(1<<lx)+1][lx][0]);
}
IL int qury_min(int le,int ri)
{if(le>ri) swap(le,ri);int lx=lg[ri-le+1];return min(ST[le][lx][1],ST[ri-(1<<lx)+1][lx][1]);
}
int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);read(have);read(n);if(have==26){scanf("%s",s+1);key=130;for(R int i=1;i<=n;++i) num[i]=s[i]-'0'+1;}else{for(R int i=1;i<=n;++i) read(num[i]),res[i]=num[i];sort(res+1,res+n+1);key=unique(res+1,res+n+1)-res-1;for(R int i=1;i<=n;++i) num[i]=lower_bound(res+1,res+key+1,num[i])-res;
//      for(R int i=1;i<=n;++i)
//      printf("%d%c",num[i],(i==n ? '\n':' '));
//      printf("key %d\n",key);}get_SA();get_hei();pre();
//  printf("SA : ");for(R int i=1;i<=n;++i) printf("%d%c",SA[i],(i==n ? '\n':' '));
//  printf("height : ");for(R int i=1;i<=n;++i) printf("%d%c",hei[i],(i==n ? '\n':' '));    for(R int i=1,tail=1;i<=n;++i){while(tail<n&&n-SA[tail]+1<i) ++tail;
//维护单调指针   ans[i]=SA[tail];int le=tail+1,ri=n,can=-1;while(le<=ri){int mid=(le+ri)>>1;if(qury_hei(tail,mid)>=i) can=mid,le=mid+1;else ri=mid-1; }
//二分那个位置 用lcp判断是否可以满足贡献出那个串        if(can!=-1) ans[i]=min(ans[i],qury_min(tail,can));
//存在的话 我们就用中间最左端的位置更新        }for(R int i=1;i<=n;++i) printf("%d%c",ans[i],(i==n ? '\n':' '));
//  fclose(stdin);
//  fclose(stdout);return 0;
}

HEOI 2019 RP++

转载于:https://www.cnblogs.com/LovToLZX/p/10590524.html

P5108 仰望半月的夜空相关推荐

  1. 洛谷 P5108 仰望半月的夜空 解题报告

    P5108 仰望半月的夜空 题目描述 半月的夜空中,寄托了多少人与人之间的思念啊 曦月知道,这些思念会汇集成一个字符串\(S(n = |S|)\) 由于思念汇集的过于复杂,因此曦月希望提炼出所有的思念 ...

  2. 洛谷P5108 仰望半月的夜空(后缀数组)

    题意 题目链接 Sol warning:下面这个做法只有95分,本地拍了1w+组都没找到错误我表示十分无能为力 我们考虑每个串的排名去更新答案,显然排名为\(1\)的后缀的前缀一定是当前长度的字典序最 ...

  3. P5108 仰望半月的夜空 SAM+线段树覆盖

    $ \color{#0066ff}{ 题目描述 }$ 半月的夜空中,寄托了多少人与人之间的思念啊 曦月知道,这些思念会汇集成一个字符串\(S(n = |S|)\) 由于思念汇集的过于复杂,因此曦月希望 ...

  4. bzoj5108 数据_【Luogu5108】仰望半月的夜空(后缀数组)

    [Luogu5108]仰望半月的夜空(后缀数组) 题面 题解 实名举报这题在比赛之前还不是这个样子的,还被我用SAM给水过去了 很明显求出$SA$之后就是按照$SA$的顺序从前往后考虑每一个长度,这样 ...

  5. luoguP5108 仰望半月的夜空 [官方?]题解 后缀数组 / 后缀树 / 后缀自动机 + 线段树 / st表 + 二分...

    仰望半月的夜空 题解 可以的话,支持一下原作吧... 这道题数据很弱..... 因此各种乱搞估计都是能过的.... 算法一 暴力长度然后判断判断,复杂度\(O(n^3)\) 期望得分15分 算法二 通 ...

  6. Luogu 5108 仰望半月的夜空(后缀数组)

    如果是要求左端点最大,直接求出SA,找前缀名次最小值就可以了.虽然现在要左端点最小,但我们已经知道了这个字典序最小的串是什么,找到名次数组上的合法区间求最小值即可.我也不知道为什么我会弃掉这个题,可能 ...

  7. 2018十二月刷题列表

    Preface \(2018\)年的尾巴,不禁感慨自己这一年的蜕变只能用蜕变来形容了. 而且老叶说我们今年没的参加清北冬令营可以参加CCF在广州二中举办的冬令营,只要联赛\(390+\)就应该可以报. ...

  8. 【背板子-后缀数组】BZOJ4199 BZOJ4650 LGP5108 CF504E

    [前言] 后缀数组一直是我没有背的板子来着. 强行背了下来. adjust这个函数丢不掉了. [题目] BZOJ4199 [NOI2015] 品酒大会 BZOJ 按heightheightheight ...

  9. oracle两表联查分组,oracle解决多表关联分组查询问题

    做了一个功能需要分组查询,同时查询A表分组查询的ID需要关联B表的数据,本来想两个表关联查询,但是报group by 语法不正确.所以做了以下修改. select count(*), cindexid ...

最新文章

  1. DARPA 2020财年研发预算 人工智能应用研究投资急剧增长
  2. 我开发了一个对.NET程序进行瘦身的工具
  3. 编码与解码 字符串中的
  4. Promise 让异步更优
  5. 深度学习(2) - 感知器
  6. UIView - CAGradientLayer
  7. 多窗直播 截屏录制——UC问鼎全球首款直播浏览器
  8. dell-xps-8930 台式机双硬盘 双系统安装 win10+Ubuntu
  9. Google推荐的图片加载库Glide介绍
  10. windows内网的情况下如何访问外网
  11. Python图片格式转换,图片压缩
  12. 快递鸟基于java功能打印电子面单api接口
  13. hifiasm对HiFi PacBio进行组装
  14. 来自Facebook的KTLS(Kernel SSL/TLS)原理和实例
  15. 【matlab】spm数据处理
  16. 一行神奇的javascript代码
  17. Kony集成百度推送-IOS
  18. 美通企业日报 | 万豪将在全球取消一次性小瓶洗漱用品;保乐力加在中国建首家麦芽威士忌酒厂...
  19. 自动控制原理实验一 典型环节及其阶跃响应
  20. 阿里云mysql测试_MySQL主主测试-阿里云开发者社区

热门文章

  1. NOIP初赛+CF某比赛 回忆录
  2. 使用uniapp开发社区交友网站的项目教程
  3. 遇到maven私服下载过慢或者卡死的情况
  4. 敏捷迭代管理 --工时估算(估点)
  5. UML——员工请假状态转换图
  6. 【面试题】深复制与浅复制的区别
  7. Git:在一个仓库中存放多个IDEA项目
  8. Greenplum数据库源码学习——FTS简介
  9. P1941 [NOIP2014 提高组] 飞扬的小鸟
  10. java 数字翻译成英文_Java实现将数字日期翻译成英文单词的工具类实例