• BZOJ4278 [ONTAK2015]Tasowanie[后缀数组+贪心]


    题目

    求两数组归并后的数组最小字典序排列。

    嘛,可能本人在贪心这块还是太弱了(或者说什么都弱),如果不知道是字符串题估计也想不起来用sa。

    显然看得出归并时字典序小的那个数组先往里面加,这就是要比较两数组后缀的rank,方法就把两串相拼做后缀排序后比较。

    这里附下贪心正确性证明,反正我不太会,只是感性认识一下。

    Upd:突然想起来这题其实可以hash+二分比较,码量稍小,不想写了

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 typedef pair<int,int> pii;
     5 template<typename T>inline char MIN(T&A,T B){return A<B?A=B,1:0;}
     6 template<typename T>inline char MAX(T&A,T B){return A>B?A=B,1:0;}
     7 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
     8 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
     9 template<typename T>inline T read(T&x){
    10     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    11     while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=getchar();return f?x=-x:x;
    12 }
    13 const int N=200000+7;
    14 int A[N<<1],a[N],b[N],l,m,n;
    15 
    16 int rk[N<<1],sa[N<<1],cnt[N<<1],y[N<<1],t=1001,p;
    17 inline void suffix_sort(){
    18     for(register int i=1;i<=l;++i)++cnt[rk[i]=A[i]];
    19     for(register int i=1;i<=t;++i)cnt[i]+=cnt[i-1];
    20     for(register int i=l;i;--i)sa[cnt[A[i]]--]=i;
    21     for(register int k=1;k<l;k<<=1,p=0){
    22         for(register int i=l-k+1;i<=l;++i)y[++p]=i;
    23         for(register int i=1;i<=l;++i)if(sa[i]>k)y[++p]=sa[i]-k;
    24         for(register int i=1;i<=t;++i)cnt[i]=0;
    25         for(register int i=1;i<=l;++i)++cnt[rk[y[i]]];
    26         for(register int i=1;i<=t;++i)cnt[i]+=cnt[i-1];
    27         for(register int i=l;i;--i)sa[cnt[rk[y[i]]]--]=y[i];
    28         swap(rk,y);rk[sa[1]]=p=1;
    29         for(register int i=2;i<=l;++i)rk[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i-1]+k]==y[sa[i]+k]?p:++p;
    30         if(p==l)break;t=p;
    31     }//for(register int i=1;i<=l;++i)printf("%d %d
    ",i,rk[i]);
    32 }
    33 //
    34 int main(){//freopen("tmp.in","r",stdin);freopen("tmp.out","w",stdout);
    35     read(n);for(register int i=1;i<=n;++i)A[i]=read(a[i]);A[n+1]=1001;
    36     read(m);for(register int i=1;i<=m;++i)A[n+i+1]=read(b[i]);A[n+m+2]=1001;
    37     l=n+m+2;suffix_sort();int i=1,j=1;
    38     while(i<=n||j<=m){
    39         if(rk[i]<rk[n+j+1])printf("%d ",a[i++]);
    40         else printf("%d ",b[j++]);
    41     }puts("");
    42     return 0;
    43 }
  • 相关阅读:
    DirectX11 With Windows SDK--14 深度测试
    DirectX11 With Windows SDK--12 深度/模板状态、平面镜反射绘制
    DirectX11--深入理解HLSL常量缓冲区打包规则
    JS学习笔记7_表单脚本
    JS学习笔记6_事件
    JS学习笔记5_DOM
    JS学习笔记4_BOM
    JS学习笔记3_函数表达式
    JS学习笔记2_面向对象
    JS学习笔记1_基础与常识
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/10355876.html
Copyright © 2020-2023  润新知