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

题目大意

有一个长度为(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;
}
原文地址:https://www.cnblogs.com/xzyf/p/13068330.html