zoukankan      html  css  js  c++  java
  • bzoj 4650(洛谷 1117) [Noi2016]优秀的拆分——枚举长度的关键点+后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4650

       https://www.luogu.org/problemnew/show/P1117

    和 bzoj2119 股市的预测 一样。

    考虑算出每个点往前的 AA 的个数和往后的 BB 的个数,每个点作为 AA 和 BB 分界点的答案累加起来就行。

    算一个点开始的 AA 的个数,就是枚举 A 的长度 L ,然后每 L 个分为一段,在段的开头求 LCP 和 LCS ,给合法的位置区间加1就行。

    一开始写成 n2 了,还能有 95 分。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int Mn(int a,int b){return a<b?a:b;}
    int Mx(int a,int b){return a>b?a:b;}
    const int N=6e4+5,K=20;
    int T,n,len,sa[N],rk[N],tp[N],tx[N],ht[N][K],lg[N],bin[K];
    int s[N],f[N],g[N]; char ch[N];
    void Rsort(int n,int nm)
    {
      for(int i=1;i<=nm;i++)tx[i]=0;
      for(int i=1;i<=n;i++)tx[rk[i]]++;
      for(int i=2;i<=nm;i++)tx[i]+=tx[i-1];
      for(int i=n;i;i--)sa[tx[rk[tp[i]]]--]=tp[i];
    }
    void get_sa(int n)
    {
      int nm=27;
      for(int i=1;i<=n;i++)tp[i]=i,rk[i]=s[i]+1;
      Rsort(n,nm);
      for(int k=1;;k<<=1)
        {
          int tot=0;
          for(int i=n-k+1;i<=n;i++)tp[++tot]=i;
          for(int i=1;i<=n;i++)
        if(sa[i]>k)tp[++tot]=sa[i]-k;
          Rsort(n,nm);memcpy(tp,rk,sizeof rk);
          nm=1; rk[sa[1]]=1;
          for(int i=2;i<=n;i++)
        {
          int u=sa[i]+k,v=sa[i-1]+k; if(u>n)u=0;if(v>n)v=0;
          rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[u]==tp[v])?nm:++nm;
        }
          if(nm==n)break;
        }
    }
    void ht_init(int n)
    {
      for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
      bin[0]=1;for(int i=1;i<=lg[n];i++)bin[i]=bin[i-1]<<1;
    }
    void get_ht(int n)
    {
      for(int i=1,k=0,j;i<=n;i++)
        {
          for((k?k--:0),j=sa[rk[i]-1];i+k<=n&&j+k<=n&&s[i+k]==s[j+k];k++);
          ht[rk[i]][0]=k;
        }
      for(int t=1;t<=lg[n];t++)
        for(int i=1;i+bin[t]-1<=n;i++)
          ht[i][t]=Mn(ht[i][t-1],ht[i+bin[t-1]][t-1]);
    }
    int qry_ht(int l,int r,bool fx)
    {
      if(l==r)return fx?sa[l]-n-1:n-sa[l]+1;
      if(l>r)swap(l,r); int d=lg[r-l];
      return Mn(ht[l+1][d],ht[r-bin[d]+1][d]);
    }
    void add(int x,int k,int *f){for(;x<=len;x+=(x&-x))f[x]+=k;}
    int qry(int x,int *f){int ret=0;for(;x;x-=(x&-x))ret+=f[x];return ret;}
    int main()
    {
      scanf("%d",&T); ht_init(60001); s[0]=30;
      while(T--)
        {
          scanf("%s",ch+1);
          n=strlen(ch+1); len=n*2+1;
          for(int i=1,j=len;i<=n;i++,j--)s[i]=s[j]=ch[i]-'a'+1;
          s[n+1]=0; get_sa(len); get_ht(len);
    
          memset(f,0,sizeof f); memset(g,0,sizeof g);
          for(int L=1,lm=n>>1,lst=0,tmp=L<<1;L<=lm;L++,lst=0,tmp+=2)
        for(int i=1;i+L<=n;i+=L)
          {
            int l2=qry_ht(rk[i],rk[i+L],0);
            int l1=qry_ht(rk[len-i+1],rk[len-i-L+1],1);
            int st=Mx(lst+1,i-l1+1);
            int en=i+l2-L;
            if(en<st)continue; lst=en;
            add(st,1,f); add(en+1,-1,f);
            add(st+tmp-1,1,g); add(en+tmp,-1,g);
          }
          ll ans=0;
          for(int i=2;i<n;i++)
        ans+=(ll)qry(i,g)*qry(i+1,f);
          printf("%lld
    ",ans);
        }
      return 0;
    }
  • 相关阅读:
    mysql常用命令
    mysql设置外网访问权限
    免费云服务部署项目
    使用虚拟主机部署Php项目总结
    github基本使用命令笔记
    git push -u origin master报错,error: failed to push some refs to 'https://github.com/Youlandawq/Qt.git' hint: Updates were rejected because the tip of your current branch is behind hint: its remote c
    centos7安装docker
    java设计模式之单例模式
    java se高级之多线程(一)
    jdbc编程
  • 原文地址:https://www.cnblogs.com/Narh/p/10331575.html
Copyright © 2011-2022 走看看