[NOI2015] 品酒大会
重要性质
根据题意,如果两个字符串是r相似的,那么他们也是1相似,2相似...r-1相似的
也就是说,我们可以从大到小的考虑限制,预处理出两个后缀的最长前缀,先处理r相似的情况,再处理r-1相似的情况,再处理r-2相似的...
要求后缀的最长前缀,我们就可以联想到SA的性质,任意两个后缀串\(S_l,S_r\)之间的最长公共前缀为\(\underset{l<i \leq{r}}{min} ht_i\)
也就是如果我们把\(ht_i\)看作点i像点i-1连一条长度为\(ht_i\)的边,那么两个点之间的最长公共前缀就是他们之间所有连边的最小值
这样我们可以将边按ht排序,从大到小加边,每次加边会对\(ht_i\)的答案产生等同于两边连通块大小乘积的贡献并将两个连通块合并
这个过程显然可以用并查集维护
ACcode:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MAXN 400010
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
struct node_dsu{
ll f[MAXN],maxz[MAXN],minz[MAXN],siz[MAXN];
// ll siz;
void mk(ll a[],ll x){
for(int i=1;i<=x;i++)maxz[i]=minz[i]=a[i],f[i]=i,siz[i]=1;
}
ll find(ll x){
return f[x]==x?x:(f[x]=find(f[x]));
}
pair<ll,ll> merge(ll x,ll y){
x=find(x),y=find(y);
ll sum=(siz[x])*(siz[y]),ans=max(max(maxz[x]*maxz[y],minz[x]*minz[y]),max(minz[x]*maxz[y],maxz[x]*minz[y]));
f[x]=y;
siz[y]+=siz[x];
maxz[y]=max(maxz[y],maxz[x]);
minz[y]=min(minz[y],minz[x]);
// maxz[y]=max()
return make_pair(sum,ans);
}
}DSU;
struct node_SA{
char c[MAXN];
ll n;
ll rk[MAXN],_rk[MAXN],sa[MAXN],ht[MAXN];
ll id[MAXN],_id[MAXN],it[MAXN];
void getin(ll x){
n=x;
for(int i=1;i<=n;i++)cin>>c[i];
}
bool cmp(ll a,ll b,ll w){
return _rk[a]==_rk[b]&&_rk[a+w]==_rk[b+w];
}
void build(){
ll m=26,p=0;
for(int i=1;i<=n;i++)it[rk[i]=c[i]-'a'+1]++;
for(int i=1;i<=m;i++)it[i]+=it[i-1];
for(int i=1;i<=n;i++)sa[it[rk[i]]--]=i;
for(int w=1;;w<<=1,m=p,p=0){
for(int i=n;i>n-w;i--)id[++p]=i;
for(int i=1;i<=n;i++)if(sa[i]>w)id[++p]=sa[i]-w;
for(int i=1;i<=m;i++)it[i]=0;
for(int i=1;i<=n;i++)it[_id[i]=rk[id[i]]]++;
for(int i=1;i<=m;i++)it[i]+=it[i-1];
for(int i=n;i;i--)sa[it[_id[i]]--]=id[i];
for(int i=1;i<=n;i++)_rk[i]=rk[i],rk[i]=0;
p=0;
for(int i=1;i<=n;i++)rk[sa[i]]=cmp(sa[i],sa[i-1],w)?p:++p;
if(p>=n)break;
}
ll k=0;
for(int i=1;i<=n;i++){
if(k)k--;
while(c[i+k]==c[sa[rk[i]-1]+k])k++;
ht[rk[i]]=k;
}
// for(int i=1;i<=n;i++)cout<<rk[i]<<" ";
// cout<<endl;
// for(int i=1;i<=n;i++)cout<<sa[i]<<" ";
// cout<<endl;
//cout<<"ht ";
// for(int i=1;i<=n;i++)cout<<ht[i]<<" ";
// cout<<endl;
}
}SA;
ll n,a[MAXN];
pair<ll,ll> s[MAXN];
ll sum[MAXN],ans[MAXN];
int main(){
cin>>n;
SA.getin(n);
SA.build();
for(int i=1;i<=n;i++)cin>>a[SA.rk[i]];
DSU.mk(a,n);
// for(int i=1;i<=n;i++)cout<<a[i]<<" ";
// cout<<endl;
for(int i=2;i<=n;i++){
s[i].first=SA.ht[i],s[i].second=i;
}
sort(s+1,s+1+n);
ll it=n;
// for(int i=1;i<=n;i++)cout<<s[i].second<<" "<<s[i].first<<endl;
ans[n]=-1e9;
for(int i=n-1;i>=0;i--){
sum[i]=sum[i+1],ans[i]=ans[i+1];
while(it){
if(s[it].first>=i){
// cout<<"it: "<<it<<" pos: "<<s[it].second<<" val: "<<s[it].first<<endl;
pair<ll,ll> p=DSU.merge(s[it].second-1,s[it].second);
sum[i]+=p.first,ans[i]=max(ans[i],p.second);
it--;
}else break;
}
// cout<<sum<<" "<<ans<<endl;
}
for(int i=0;i<=n-1;i++)cout<<sum[i]<<" "<<((ans[i]==-1e9)?0:ans[i])<<endl;
return 0;
}

浙公网安备 33010602011771号