P5108 仰望半月的夜空

传送门

这是一个比较不正常的写法……估计应该没几个和我这样写的……

我们考虑倒着做,也就是依次考虑长度为(n,n-1,...,1)时的答案。发现长度为(n)时只能选第一个位置,为(n-1)时要选(1,2)中较优的位置……

然后大力猜想一发倒着的答案是否保证不降,然而样例一直接把脸给打得啪啪疼

然而倒着的时候答案的确有一个性质。比方说长度为(len)的时候有(i<j)(i)(j)更优,那么(j)就永远不可能是最优答案了。因为长度不断减小的时候永远满足(i)开头的字典序比(j)小或者两个字典序相等但(i)在更左边

于是就可以用单调栈了。每一次把新的可以作为答案的点加进去,然后判断(st[top-1])是否比(st[top])更优,不断弹出,最后把栈顶最为当前长度的答案即可

然而现在的问题就是怎么判更优,毕竟要比较字典序。我太菜了不会写SAM和SA之类的(不过话说这两个能不能弄也不知道啊……)于是想了一个比较鬼畜的办法:用(hash+)二分判断两个串相等的长度,那么只要比较它们下一位的大小就好了

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
    if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]=' ';
}
const int N=3e5+5;
int a[N],b[N],st[N],ans[N];
int n,top,op,m;char s[N];
struct Hash{
    int Base,P,bin[N],sum[N];
    inline void init(R int base,R int p){
        P=p,Base=base,bin[0]=1;
        fp(i,1,n)bin[i]=1ll*bin[i-1]*Base%P;
        fp(i,1,n)sum[i]=(1ll*sum[i-1]*Base+a[i]+1)%P;
    }
    inline int gethash(R int l,R int r){return (sum[r]-1ll*sum[l-1]*bin[r-l+1]%P+P)%P;}
}h1,h2;
inline bool equal(int l,int r,int ql,int qr){
    return h1.gethash(l,r)==h1.gethash(ql,qr)&&h2.gethash(l,r)==h2.gethash(ql,qr);
}
bool check(int ql,int qr,int len){
    if(equal(ql,ql+len-1,qr,qr+len-1))return true;
    int l=1,r=len,ans=0,mid;
    while(l<=r){
        mid=(l+r)>>1;
        if(equal(ql,ql+mid-1,qr,qr+mid-1))l=mid+1,ans=mid;else r=mid-1;
    }return a[ql+ans]<=a[qr+ans];
}
int main(){
//	freopen("testdata.in","r",stdin);
    scanf("%d%d",&op,&n);
    if(op==26){
        m=35,scanf("%s",s+1);fp(i,1,n)a[i]=s[i]-'a';
    }else{
        fp(i,1,n)a[i]=b[i]=read();sort(b+1,b+1+n),m=unique(b+1,b+1+n)-b-1;
        fp(i,1,n)a[i]=lower_bound(b+1,b+1+n,a[i])-b;
    }h1.init(233,1e9+7),h2.init(19260817,998244353);
    fp(i,1,n){
        st[++top]=i;while(top>1&&check(st[top-1],st[top],n-i+1))--top;
        ans[n-i+1]=st[top];
    }fp(i,1,n)print(ans[i]);return Ot(),0;
}
原文地址:https://www.cnblogs.com/bztMinamoto/p/10138205.html