并不对劲的loj3095:p5329:[SNOI2019]字符串

题目大意

有一个长度为\(n\)的字符串\(s_1,...,s_n\)
用它生成的\(n\)个长度为\(n-1\)的串,\(i\)号串是\(s_1,...,s_{i-1},s_{i+1},...,s_n\)
将这\(n\)个串按字典序排序,字典序相同的编号小的排前面,输出编号的顺序。
\(n\leq 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;
}
posted @ 2020-06-08 20:39  echo6342  阅读(161)  评论(0编辑  收藏  举报