萌新妹子刚学简单绿求调
查看原帖
萌新妹子刚学简单绿求调
556545
_anll_楼主2024/11/5 14:16

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;
}
2024/11/5 14:16
加载中...