正题
题目链接:https://jzoj.net/senior/#main/show/1247
题目大意
一个长度为nnn的字符串,每次选择头或者尾加入新的字符串末端,求字典序最小的新的字符串。
解题思路
我们发现若剩下的字符串比翻转之后份字符串字典序大那么就加入头,否则就加入尾。所以我们之间判定就是O(n2)O(n^2)O(n2)的,但是这样的时间复杂度不够优秀。
我们考虑字符串hashhashhash,比较字典序要找到第一个不同的位置,我们二分一下那个位置字符串hashhashhash判定即可。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define ull unsigned long long
using namespace std;
const int N=31000;
const ull p=13331;
int n,z;char c[N];
ull f[N],g[N],pow[N];
ull getf(int l,int r)
{return f[r]-f[l-1]*pow[r-l+1];}
ull getg(int l,int r)
{return g[l]-g[r+1]*pow[r-l+1];}
int main()
{scanf("%d",&n);pow[0]=1;for(int i=1;i<=n;i++)cin>>c[i],pow[i]=pow[i-1]*p;for(int i=1;i<=n;i++)f[i]=f[i-1]*p+c[i]-'A'+1;for(int i=n;i>=1;i--)g[i]=g[i+1]*p+c[i]-'A'+1;int L=1,R=n;for(int i=1;i<=n;i++){int l=0,r=R-L;while(l<=r){int mid=(l+r)/2;if(getf(L,L+mid)==getg(R-mid,R)) l=mid+1;else r=mid-1;}if(c[L+l]<c[R-l]) putchar(c[L++]);else putchar(c[R--]);z++;if(z%80==0) putchar('\n');}
}