D. 给你一个字符串,你现在需要的是将它的每一个前缀看成单独的字符串,最终组成最大的一个整数。
分析,可以想到,两个前缀A,B组成的字符串,其大小由相对顺序决定,不妨设|A|<|B|。B=A+X,则最终的大小取决于A+X于X+A的字典序大小。这个直接通过SA就可以解决。最终通过排序来解决。
#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
const int MOD = 998244353;
int sa[N], rk[N], c[N], h[N], x[N], y[N];
int rmq[N][21], n, base=10;
int lg[N], pw[N], arr[N], val[N];
char s[N];
void SA(){
int m=256;
for(int i=1;i<=m;++i)c[i]=0;
for(int i=1;i<=n;++i)++c[x[i]=s[i]];
for(int i=1;i<=m;++i)c[i]+=c[i-1];
for(int i=n;i>=1;--i)sa[c[s[i]]--]=i;
for(int k=1,p;k<=n;k<<=1){
p=0;
for(int i=n;i>n-k;--i)y[++p]=i;
for(int i=1;i<=n;++i){
if(sa[i]>k){
y[++p]=sa[i]-k;
}
}
for(int i=1;i<=m;++i)c[i]=0;
for(int i=1;i<=n;++i)++c[x[i]];
for(int i=1;i<=m;++i)c[i]+=c[i-1];
for(int i=n;i>=1;--i)sa[c[x[y[i]]]--]=y[i];
p=y[sa[1]]=1;
for(int i=2,a,b;i<=n;++i){
a=(sa[i]+k>n?-1:x[sa[i]+k]);
b=(sa[i-1]+k>n?-1:x[sa[i-1]+k]);
y[sa[i]]=(x[sa[i]]==x[sa[i-1]]&&a==b?p:++p);
}
if(p>=n)break;
m=p;
swap(x,y);
}
for(int i=1;i<=n;++i){
rk[sa[i]]=i;
}
}
void getHeight(){
for(int i=1, k=0;i<=n;++i){
if(k)--k;
int j=sa[rk[i]-1];
while(s[i+k]==s[j+k])++k;
h[rk[i]]=k;
}
}
void init(){
SA();
getHeight();
for(int i=1;i<=n;++i)rmq[i][0]=h[i];
for(int j=1;j<=20;++j){
for(int i=1;i+(1<<j)-1<=n;++i){//bug
rmq[i][j]=min(rmq[i][j-1],rmq[i+(1<<j-1)][j-1]);
}
}
}
int LCP(int l, int r){
l=rk[l];r=rk[r];
++l,++r;
if(l>r)swap(l,r);
--r;
int k=lg[r-l+1];
return min(rmq[l][k],rmq[r-(1<<k)+1][k]);
}
bool cmp(int l, int r){
if(l>r)return !cmp(r,l);
int c=LCP(1,l+1);
int len=r-l;
if(c<len){
return rk[l+1]<rk[1];
}else{
return rk[1]<rk[len+1];
}
}
int main(){
lg[0]=-1;
for(int i=1;i<=100000;++i)lg[i]=lg[i>>1]+1;
scanf("%s", s+1);
n=strlen(s+1);
init();
pw[0]=1;
for(int i=1;i<=n;++i){
val[i]=(1ll*val[i-1]*base+s[i]-'0')%MOD;
pw[i]=1ll*pw[i-1]*base%MOD;
arr[i]=i;
}
sort(arr+1,arr+n+1,cmp);
int ans=0;
for(int i=1;i<=n;++i)ans=(1ll*ans*pw[arr[i]]+val[arr[i]])%MOD;
if(ans<0)ans+=MOD;
printf("%d",ans);
return 0;
}
其他题都没啥营养,咕咕咕。