题目大意
有一个长度为(n)的字符串(s_1,...,s_n)。
用它生成的(n)个长度为(n-1)的串,(i)号串是(s_1,...,s_{i-1},s_{i+1},...,s_n)。
将这(n)个串按字典序排序,字典序相同的编号小的排前面,输出编号的顺序。
(nleq 10^6;)
题解
比较(x)号串和(y)号串((x<y))的过程:比较(s_1,...,s_{x-1},s_{x+1},...,s_n),(s_1,...,s_{y-1},s_{y+1},...,s_n)。
注意到(s_1,...,s_{x-1})和(s_{y+1},...,s_n)这两部分在这两个串中都出现了,而且出现的位置相同,可以不考虑。
就变成比较(s_{x+1},...,s_y)和(s_x,...,s_{y-1})。
这部分如果都是同一个字母,就可以直接把(x)排前面;否则,第一个与(s_x)不同的字母先在(s_{x+1},...,s_y)中出现,那么该字母与(s_x)的大小关系就是(x)号串与(y)号串的大小关系。
先求每个位置后第一个与它不同的字母的位置,再改改sort的cmp。
代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 1000007
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
if(x==0){putchar('0'),putchar(' ');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar(' ');
return;
}
int n,ord[maxn],p[maxn],fh[maxn];
char s[maxn];
bool cmp(int x,int y)
{
if(x==y)return 0;
int rev=0;
if(x>y)swap(x,y),rev=1;
if(p[x]>=y)return rev^1;
else return fh[x]==-1?(rev^1):rev;
}
int main()
{
scanf("%d%s",&n,s+1);
dwn(i,n,1)
{
ord[i]=i;
if(i==n)p[i]=n+1;
else if(s[i]!=s[i+1])p[i]=i,fh[i]=(s[i+1]<s[i])?-1:1;
else p[i]=p[i+1],fh[i]=fh[i+1];
}
sort(ord+1,ord+n+1,cmp);
rep(i,1,n)write(ord[i]);
return 0;
}