rt,思路和题解后几篇差不多,都是从当前点去找左/右边第一个比自己小的,但实现用的是单调栈+二分+hash,只过了 #1 #2 #7 #8 这四个点,求大佬捞捞 QAQ!
#include<iostream>
#include<algorithm>
#define C 8281027
#define fir first
#define sec second
#define int long long
using namespace std;
const int N=3005,mod=1e9+7;
int n,num[N],has[N],bas[N],stk[N],L[N],R[N],dif[N],ans[N];
string s;
bool check(int x,int y,int mid){
return (has[x+mid-1]-has[x-1]*bas[mid]%mod==has[y+mid-1]-has[y-1]*bas[mid]%mod);
}
int Mid(int x,int y,int r){
int l=1,mid=0,an=0;
while(l<=r){
mid=(l+r)/2;
if(check(x,y,mid)) l=mid+1,an=mid;
else r=mid-1;
}
return an;
}
signed main(){
// freopen("gen.in","r",stdin);
// freopen("work.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>s;s='6'+s;bas[0]=1;
for(int i=1;i<=n;i++) bas[i]=bas[i-1]*C%mod;
for(int i=1;i<=n;i++) has[i]=(has[i-1]*C%mod+(s[i]-'A'+1))%mod;
for(int i=1;i<=n;i++){//枚举长度
int l=1,r=0;stk[r]=0;
for(int j=1;j+i-1<=n;j++){
while(l<=r){
int x=Mid(stk[r],j,i);
if(x==i) break;
if(s[stk[r]+x]<=s[j+x]) break;
r--;
}
L[j]=stk[r]+1;stk[++r]=j;
}
l=1,r=0;stk[r]=n+2-i;
for(int j=n+1-i;j>=1;j--){
while(l<=r){
int x=Mid(stk[r],j,i);
if(x==i){r--;continue;}
if(s[stk[r]+x]<s[j+x]) break;
r--;
}
R[j]=stk[r]-1;stk[++r]=j;
}
for(int j=1;j+i-1<=n;j++){
dif[i]++,dif[R[j]+i-L[j]+1]--;
}
int an=0;
for(int j=1;j<=n;j++){
stk[j]=num[j]=0;
an+=dif[j];dif[j]=0;
ans[an]++;
}
}
for(int i=1;i<=n;i++) cout<<ans[i]<<endl;
return 0;
}