Luogu P2178 [NOI2015]品酒大会

题意:对于每个 (k) ,求 (S[p,p+k-1]==S[q,q+k-1],(p,q)为无序二元组) 的方案数,并求出在 (k) 一定时,(vl[p] imes vl[q]) 的最大值。

(SA) 并查集:我们把 (ht[]) 当做边,合并时计算两个集合产生的贡献;

好像还可以单调栈+ST表做吧(没写。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
  register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
  do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=300010;
int n,a[N],sa[N],rk[N],ht[N],c[N],x[N],y[N];
char s[N];
inline void init() {
  R m=122;
  for(R i=1;i<=n;++i) ++c[x[i]=s[i]];
  for(R i=2;i<=m;++i) c[i]+=c[i-1];
  for(R i=n;i;--i) sa[c[x[i]]--]=i;
  for(R t=1,top=0;top<n;m=top,t<<=1) {
    top=0;
    for(R i=n-t+1;i<=n;++i) y[++top]=i;
    for(R i=1;i<=n;++i) if(sa[i]>t) y[++top]=sa[i]-t;
    memset(c,0,(m+1)<<2);
    for(R i=1;i<=n;++i) ++c[x[i]];
    for(R i=2;i<=m;++i) c[i]+=c[i-1];
    for(R i=n;i;--i) sa[c[x[y[i]]]--]=y[i];
    swap(x,y),x[sa[1]]=top=1;
    for(R i=2;i<=n;++i)
      x[sa[i]]=(y[sa[i]]==y[sa[i-1]] && y[sa[i]+t]==y[sa[i-1]+t])?top:++top;
  } for(R i=1;i<=n;++i) rk[sa[i]]=i;
  R k=0;
  for(R i=1,j;i<=n;++i) {
    if(k) --k; j=sa[rk[i]-1];
    while(s[i+k]==s[j+k]) ++k;
    ht[rk[i]]=k;
  }
}
struct node {
  int ht,id;
  inline bool operator < (const node& that) const 
    {return ht>that.ht;}
}b[N];
int fa[N],sz[N],mx[N],mn[N]; ll ans[N],anss[N];
inline int getf(int x) {return x==fa[x]?x:fa[x]=getf(fa[x]);}
inline void merge(int u,int v,int t) {
  R fu=getf(u),fv=getf(v);
  if(sz[fu]>sz[fv]) swap(u,v),swap(fu,fv);
  ans[t]+=1ll*sz[fu]*sz[fv];
  anss[t]=max(1ll*anss[t],max(1ll*mx[fu]*mx[fv],1ll*mn[fu]*mn[fv]));
  mx[fv]=max(mx[fv],mx[fu]);
  mn[fv]=min(mn[fv],mn[fu]);
  fa[fu]=fv,sz[fv]+=sz[fu];
}
inline void main() {
  n=g(),scanf("%s",s+1);
  for(R i=1;i<=n;++i) a[i]=g();
  init();
  for(R i=1;i<=n;++i) b[i].ht=ht[i],b[i].id=i;
  sort(b+2,b+n+1);
  memset(anss,0xbf,sizeof anss);
  for(R i=1;i<=n;++i) fa[i]=i,sz[i]=1,mx[i]=mn[i]=a[i];
  for(R i=2;i<=n;++i) 
    merge(sa[b[i].id-1],sa[b[i].id],b[i].ht);
  for(R i=n-1;~i;--i) 
    ans[i]+=ans[i+1],anss[i]=max(anss[i],anss[i+1]);
  for(R i=0;i<n;++i) 
    if(ans[i]) printf("%lld %lld
",ans[i],anss[i]);
    else puts("0 0");
}
} signed main() {Luitaryi::main(); return 0;}

(SAM) 把串倒着插,每个点的贡献即为 (以i为根的路径条数 imes 产生的最值) 转移时类似淀粉质(详见代码)

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
  register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
  do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=600010,Inf=0x3f3f3f3f;
int n,tot=1,lst=1;
int fa[N],c[N][26],len[N],a[N],vl[N],sz[N];
char s[N>>1];
ll ans1[N>>1],ans2[N>>1];
inline void add(int ch) {
  R p=lst,np=lst=++tot;
  len[np]=len[p]+1; sz[np]=1;
  while(p&&!c[p][ch]) c[p][ch]=np,p=fa[p];
  if(!p) return fa[np]=1,void();
  R q=c[p][ch];
  if(len[q]==len[p]+1) return fa[np]=q,void();
  R nq=++tot;
  memcpy(c[nq],c[q],26<<2);
  fa[nq]=fa[q],len[nq]=len[p]+1;
  fa[np]=fa[q]=nq;
  while(p&&c[p][ch]==q) c[p][ch]=nq,p=fa[p];
}
int cnt,vr[N],nxt[N],fir[N],mx[N],mn[N];
inline void add(int u,int v) 
  {vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
inline void dfs(int u) {
  if(sz[u]) mx[u]=mn[u]=vl[u];
  else mx[u]=-Inf,mn[u]=Inf;
  for(R i=fir[u];i;i=nxt[i]) {
    R v=vr[i];
    dfs(v);
    if(mx[u]!=-Inf&&mn[u]!=Inf&&mx[v]!=-Inf&&mn[v]!=Inf)
      ans1[len[u]]=max(ans1[len[u]],max(1ll*mx[u]*mx[v],1ll*mn[u]*mn[v]));
    mx[u]=max(mx[u],mx[v]);
    mn[u]=min(mn[u],mn[v]);
    ans2[len[u]]+=1ll*sz[u]*sz[v];
    sz[u]+=sz[v];
  }
}
inline void main() {
  n=g(),scanf("%s",s+1);
  for(R i=1;i<=n;++i) a[i]=g();
  for(R i=n;i;--i) add(s[i]-'a'),vl[lst]=a[i];
  for(R i=2;i<=tot;++i) add(fa[i],i);
  memset(ans1,0xcf,sizeof ans1); dfs(1); 
  for(R i=n-1;~i;--i) 
    ans1[i]=max(ans1[i],ans1[i+1]),
    ans2[i]+=ans2[i+1];
  for(R i=0;i<n;++i) if(ans2[i])
      printf("%lld %lld
",ans2[i],ans1[i]);
    else puts("0 0");
}
} signed main() {Luitaryi::main(); return 0;}

2019.01.09

原文地址:https://www.cnblogs.com/Jackpei/p/12177332.html