传送门

显然要写一个排序,那只要考虑cmp函数怎么写就行了.第\(i\)个字符串和第

\(j\)个,首先前\(min(i,j)-1\)个字符是相同的,然后就是要比较后缀\(min(i,j)\)和\(min(i,j)+1\),先求lcp(要对\(max(i,j)-min(i,j)\)取\(min\)),如果两个后缀往后跳lcp的位置字符不一样就可以得到结果了.

然后可以用SA求lcp 然后我T了,但是可以发现所有lcp都是相邻两个后缀的,所以这个可以\(O(n)\)递推

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#include<ctime>
#include<queue>
#include<map>
#include<set>
#define LL long long
#define db double using namespace std;
const int N=2e6+10;
int rd()
{
int x=0,w=1;char ch=0;
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
} char cc[N];
int /*sa[N],rk[N],wr[N],wx[N],bk[N],*/he[N]/*,mi[N][21],L2[N]*/,n,an[N];
/*void inii()
{
int sz=128,p=0,j=1;
for(int i=1;i<=n;++i) ++bk[rk[i]=cc[i]];
for(int i=1;i<=sz;++i) bk[i]+=bk[i-1];
for(int i=n;i;--i) sa[bk[rk[i]]--]=i;
while(p<n)
{
int tp=0;
for(int i=n-j+1;i<=n;++i) wx[++tp]=i;
for(int i=1;i<=n;++i) if(sa[i]>j) wx[++tp]=sa[i]-j;
for(int i=1;i<=n;++i) wr[i]=rk[wx[i]];
for(int i=1;i<=sz;++i) bk[i]=0;
for(int i=1;i<=n;++i) ++bk[wr[i]];
for(int i=1;i<=sz;++i) bk[i]+=bk[i-1];
for(int i=n;i;--i) sa[bk[wr[i]]--]=wx[i];
for(int i=1;i<=n;++i) wr[i]=rk[i];
rk[sa[1]]=p=1;
for(int i=2;i<=n;++i) rk[sa[i]]=p+=!(wr[sa[i]]==wr[sa[i-1]]&&wr[sa[i]+j]==wr[sa[i-1]+j]);
sz=p,j<<=1;
}
for(int i=1;i<=n;++i)
{
if(he[rk[i-1]]) he[rk[i]]=he[rk[i-1]]-1;
int j=sa[rk[i]-1];
while(cc[i+he[rk[i]]]==cc[j+he[rk[i]]]) ++he[rk[i]];
}
for(int i=2;i<=n;++i) L2[i]=L2[i>>1]+1;
for(int i=1;i<=n;++i) mi[i][0]=he[i];
for(int j=1;j<=L2[n];++j)
for(int i=1;i+(1<<j)-1<=n;++i)
mi[i][j]=min(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);
}
int lcp(int i,int j)
{
if(i==j) return n;
i=rk[i],j=rk[j];
if(i>j) swap(i,j);
++i;
int z=L2[j-i+1];
return min(mi[i][z],mi[j-(1<<z)+1][z]);
}*/
bool cmp(int i,int j)
{
/*int ii,jj;
if(i<j) ii=i+1,jj=i;
else ii=j,jj=j+1;
int len=lcp(ii,jj);
if(ii<i) len=min(len,i-ii);
if(jj<j) len=min(len,j-jj);
ii+=len,jj+=len;
ii+=ii==i,jj+=jj==j;
if(cc[ii]!=cc[jj]) return cc[ii]<cc[jj];
return i<j;*/
int ii=min(i,j),lm=max(i,j)-ii,len=he[ii+1];
if(len>=lm) return i<j;
return (cc[ii+len]<cc[ii+1+len])^(i<j);
} int main()
{
n=rd();
scanf("%s",cc+1);
for(int i=2;i<=n;++i)
{
if(he[i-1]) he[i]=he[i-1]-1;
while(cc[i+he[i]]==cc[i-1+he[i]]) ++he[i];
}
for(int i=1;i<=n;++i) an[i]=i;
sort(an+1,an+n+1,cmp);
for(int i=1;i<=n;++i) printf("%d ",an[i]);
return 0;
}

luogu P5329 [SNOI2019]字符串的更多相关文章

  1. [洛谷P5329][SNOI2019]字符串

    题目大意:给一个长度为$n$的字符串$s$,字符串$p_i$为字符串$s$去掉第$i$个字符后形成的字符串.请给所有字符串$p_i$排序(相同字符串按编号排序) 题解:先去掉所有连续相同字符,因为它们 ...

  2. 洛谷$P5329\ [SNOI2019]$字符串 字符串

    正解:字符串 解题报告: 传送门$QwQ$ 有两个很妙的方法,分别港下$QwQ$ 首先为了表示方便,这里和题面一样设$s_i$表示去掉第$i$个字母得到的字符串.另设$lcp(i,j)$表示$suf_ ...

  3. 【LOJ#3095】[SNOI2019]字符串(后缀数组)

    [LOJ#3095][SNOI2019]字符串(后缀数组) 题面 LOJ 题解 首先画图看看如何比较两个串的大小,发现这个东西等价于求两个相邻的后缀的\(LCP\). 一个做法是求出\(SA\),然后 ...

  4. 题解 P5329 【[SNOI2019]字符串】

    用栈的做法来水一发. 首先我们有一个暴力的做法,枚举每个被删除的字符,然后排序输出,时间复杂度:$ O ( N \times N \times LogN ) $ . 然后我们观察一下数据,发现有一个数 ...

  5. Luogu 1071 - 潜伏者 - [字符串]

    题目链接:https://www.luogu.org/problemnew/show/P1071 题解: 模拟就完事儿了. 注意failed的情况有:出现一个 $f[x]$ 对应多个值:存在两个不同的 ...

  6. [SNOI2019]字符串

    名称:字符串 来源:2019年陕西省选 题目内容 传送门 洛谷(P5392) 题目描述 给出一个长度为$n$的由小写字母组成的字符串$a$,设其中第$i$个字符为$a_i(1≤i≤n)$. 设删掉第$ ...

  7. luogu P4302 [SCOI2003]字符串折叠

    题目描述 折叠的定义如下: 一个字符串可以看成它自身的折叠.记作S = S X(S)是X(X>1)个S连接在一起的串的折叠.记作X(S) = SSSS-S(X个S). 如果A = A', B = ...

  8. Luogu P2679 子串(字符串+dp)

    P2679 子串 题意 题目描述 有两个仅包含小写英文字母的字符串\(A\)和\(B\). 现在要从字符串\(A\)中取出\(k\)个互不重叠的非空子串,然后把这\(k\)个子串按照其在字符串\(A\ ...

  9. luogu P6088 [JSOI2015]字符串树 可持久化trie 线段树合并 树链剖分 trie树

    LINK:字符串树 先说比较简单的正解.由于我没有从最简单的考虑答案的角度思考 所以... 下次还需要把所有角度都考察到. 求x~y的答案 考虑 求x~根+y~根-2*lca~根的答案. 那么问题变成 ...

随机推荐

  1. sh_07_continue

    sh_07_continue i = 0 while i < 10: # continue 某一条件满足时,不执行后续重复的代码 # i == 3 if i == 3: # 注意:在循环中,如果 ...

  2. mac 的 ping 命令怎么停掉?

    Widnows下的Ping不会只Ping4次,mac 会不停的Ping下去,需要停止,按下键盘上的 control+c 键即可停掉 Ping 过程.

  3. Selenium 定位一组元素

    到目前为止,我们已经知道了怎么去定位一个元素,有时候我们需要获取页面上的多个元素,该怎么办呢?难道还一个一个地去定位,那也太lower了吧. webdriver提供了定位一组元素的方法,跟前面讲的那八 ...

  4. 南京网络赛C

    分段打表大法好!!! 打表40min,A题1s https://nanti.jisuanke.com/t/41300 #include<bits/stdc++.h> #define int ...

  5. Sql 中的as是什么意思 + 无列名注入解析

    相当于取别名 这里结合一下无列名注入的知识点: 这种方法在第十届SWPUCTF的web1——广告招租里考到了:

  6. Java中参数的引用传递和值传递

    1.一些定义 值传递:把实际传入参数的值,在内存中赋值一份 引用传递:传入的是实际参数的地址 2.传递基本类型的参数 因为Java是值传递,那就不难理解下面的代码不交换任何值 swap(Type ar ...

  7. Linux读写执行权限

    Linux 将访问文件的用户分为 3 类,分别是文件的所有者,所属组(也就是文件所属的群组)以及其他人. 最常见的文件权限有 3 种,即对文件的读(用 r 表示). 写(用 w 表示). 执行(用 x ...

  8. jQuery-validate插件初级篇

    特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...

  9. C# DataTable 增加行与列

    亲测有用的方法 DataTable AllInfos = new DataTable();//生成一个表格 DataColumn typeColumn = new DataColumn();//建一个 ...

  10. 使用resultMap定义查询结果集,实现关联查询

    接下来介绍resultMap定义查询结果集,实现关联查询 1 首先在接口中定义操作的方法 public interface EmployeeMapperPlus { public Employee g ...