• bzoj 4278 Tasowanie —— 后缀数组


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

    每次取两个后缀中字典序较小的那个的首字符;

    注意超出去的部分是 inf 而不是 0,因为如果到了比较超出去部分的时候,那就是一个串走到了末尾而另一个没有(或者都到末尾,不过都到末尾就随便选啦),而且两个后缀的 LCP 顶到了末尾;

    这时选长度较长的比较优,因为反正 LCP 处一样,先选较短的等选完以后还是得过来,不如先选较长的,也许后面还出现更优的。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int const xn=4e5+5;
    int n,m,mx,a[xn>>1],b[xn>>1],s[xn],tp[xn],sa[xn],rk[xn],tax[xn];
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    void Rsort()
    {
      int len=n+m;
      for(int i=1;i<=mx;i++)tax[i]=0;
      for(int i=1;i<=len;i++)tax[rk[tp[i]]]++;
      for(int i=1;i<=mx;i++)tax[i]+=tax[i-1];
      for(int i=len;i;i--)sa[tax[rk[tp[i]]]--]=tp[i];
    }
    int ps(int nw,int k)
    {
      if(nw<=n&&nw+k>n)return 0;
      return nw+k;
    }
    void work()
    {
      int len=n+m;
      for(int i=1;i<=len;i++)rk[i]=s[i],tp[i]=i;
      Rsort(); int up=max(n,m);
      for(int k=1;k<=up;k<<=1)
        {
          int num=0;
          //for(int i=len-k+1;i<=len;i++)tp[++num]=i;
          //for(int i=n-k+1;i<=n;i++)tp[++num]=i;
          for(int i=1;i<=len;i++)
        if((sa[i]<=n&&sa[i]>k)||(sa[i]>n&&sa[i]>n+k))tp[++num]=sa[i]-k;
          for(int i=len-k+1;i<=len;i++)tp[++num]=i;
          for(int i=n-k+1;i<=n;i++)tp[++num]=i;
          Rsort(); swap(rk,tp);
          rk[sa[1]]=1; num=1;
          for(int i=2;i<=len;i++)
        rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[ps(sa[i],k)]==tp[ps(sa[i-1],k)])?num:++num;
          if(num==len)break;
          mx=num;
        }
    }
    int main()
    {
      n=rd(); for(int i=1;i<=n;i++)a[i]=rd(),s[i]=a[i],mx=max(mx,a[i]);
      m=rd(); for(int i=1;i<=m;i++)b[i]=rd(),s[n+i]=b[i],mx=max(mx,b[i]);
      work();
      int p1=1,p2=1;
      while(p1<=n&&p2<=m)
        {
          if(rk[p1]<rk[n+p2])printf("%d ",a[p1++]);
          else printf("%d ",b[p2++]);
        }
      if(p1>n)while(p2<=m)printf("%d ",b[p2++]);
      if(p2>m)while(p1<=n)printf("%d ",a[p1++]);
      puts("");
      return 0;
    }
  • 相关阅读:
    [CF538F]A Heap of Heaps(主席树)
    [BZOJ1901][luogu2617]Dynamic Rankings(树状数组+主席树)
    [BZOJ3932][CQOI2015]任务查询系统(差分+主席树)
    [BZOJ2588]Count on a tree(LCA+主席树)
    [BZOJ2733][HNOI2012] 永无乡(线段树合并)
    [BZOJ1604][Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 (Treap+单调队列)
    【贪心】POJ2376-Cleaning Shifts
    【穷竭】POJ3187-Backward Digit Sums
    【枚举+贪心】POJ2718-Smallest Difference
    【BFS】POJ3669-Meteor Shower
  • 原文地址:https://www.cnblogs.com/Zinn/p/10075772.html
Copyright © 2020-2023  润新知