zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    PHP 函数大集合
    PHP 单词集合
    PHP 常用函数集合
    Linux 服务器中搭建环境
    windows下cmd中命令操作
    TP中的AJAX返回ajaxReturn()
    PHP面试题
    CI表单验证
    CI数据库操作_查询构造器类
    react 的核心思想 【声名式】Declarative 的理解
  • 原文地址:https://www.cnblogs.com/Jackpei/p/12177332.html
Copyright © 2011-2022 走看看