题解:P10279 [USACO24OPEN] The 'Winning' Gene S
区区
Solution P10279
Idea
考虑枚举
紧接着枚举序列,然后把子串预处理出来。
记
接下来基本套路:把枚举型问题转化为贡献型问题。考虑一个子串
那么需要找到
然后设字典序小于
但是问题是:普通整数的比较是
于是考虑优化。
- 记忆化优化。
不难发现如果有两个字符串
- 类当前弧优化。
不难发现什么数据会把我们卡住呢?就像这样的:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
每一次我们需要比较这两个字符串,都需要从
这样你就能卡过去。
::::success[AC Code]
#include<bits/stdc++.h>
using namespace std;
const int N=3005;
string s;
char ch[N][N];
int n;
int ans[N][N],cnt[N];
int L[N],R[N];
stack<int>st;
int f[N][N],g[N][N];
int h[N][N],o[N][N];
bool biggerb(int p1,int p2,int len,char s1[],char s2[]){
if(f[p1][p2]==1)return true;
if(f[p1][p2]==-1)return false;
for(int i=h[p1][p2]+1;i<=len;i++){
if(s1[i]>s2[i]){
f[p1][p2]=1;
return true;
}
if(s1[i]<s2[i]){
f[p1][p2]=-1;
return false;
}
}
h[p1][p2]=len;
return false;
}
bool biggere(int p1,int p2,int len,char s1[],char s2[]){
if(g[p1][p2]==1)return true;
if(g[p1][p2]==-1)return false;
for(int i=o[p1][p2]+1;i<=len;i++){
if(s1[i]>s2[i]){
g[p1][p2]=1;
return true;
}
if(s1[i]<s2[i]){
g[p1][p2]=-1;
return false;
}
}
o[p1][p2]=len;
return true;
}
int main(){
cin>>n>>s;s=' '+s;
for(int len=1;len<=n;len++){
for(int l=1,r=len;r<=n;l++,r++){
ch[l][len]=s[r];
}
while(!st.empty())st.pop();
for(int l=1,r=len;r<=n;l++,r++){
while(!st.empty()&&biggerb(st.top(),l,len,ch[st.top()],ch[l])){
st.pop();
}
if(!st.empty())L[l]=st.top()+1;
else L[l]=1;
st.push(l);
}
while(!st.empty())st.pop();
for(int r=n,l=n-len+1;l>=1;l--,r--){
while(!st.empty()&&biggere(st.top(),l,len,ch[st.top()],ch[l])){
st.pop();
}
if(!st.empty())R[l]=st.top()-1;
else R[l]=n-len+1;
st.push(l);
}
for(int l=1,r=len;r<=n;l++,r++){
ans[1][len]++;ans[R[l]-L[l]+2][len]--;
}
}
for(int len=1;len<=n;len++){
for(int i=1;i<=n;i++){
ans[i][len]+=ans[i-1][len];
cnt[ans[i][len]]++;
}
}
for(int i=1;i<=n;i++)cout<<cnt[i]<<'\n';
return 0;
}
::::