zoukankan      html  css  js  c++  java
  • [atARC114F]Permutation Division

    由于是排列,即任意两个数字都各不相同,因此字典序最大的$q_{i}$就是将每一段的第一个数从大到小排序

    接下来,考虑第一个元素,也就是每一段开头的最大值,分类讨论:

    1.当$p_{1}le k$时,取$1,2,...,k$为每一段开头是唯一一种可以使$q_{i}$以$k$为开头的方案(证明略)

    2.当$p_{1}>k$时,假设这$k$个块的开头依次为$a_{1},a_{2},...,a_{k}$(其中$a_{1}=1$),将其按照开头的数字从大到小排序后,依次为$b_{1},b_{2},...,b_{k}$

    考虑$a_{i}$和$b_{i}$的最长公共前缀,假设为$l$(即$forall 1le ile l,a_{i}=b_{i}$且$a_{l+1} e b_{l+1}$),根据$b$是$a$排序得到,那么$l$还可以用另一种方式来描述:最大的$l$满足$p_{a_{1}}>p_{a_{2}}>...>p_{a_{l}}>max_{i=l+1}^{k}p_{a_{i}}$

    更进一步的,注意下面这两个性质:

    1.$q_{i}$的字典序是随着$k$的减小而单调不增的,即在同样的情况下,我们希望$k$小(当$k$缩小时,只需要将任意两段合并,$q_{i}$字典序显然不增)

    2.取$k=1$时即$q=p$,根据性质1即可得$qge p$,那么$q_{i}$最小的必要条件是其与$p_{i}$的最长公共前缀最长

    继续前面的思路,不难发现$a_{l+1}-1$其实就是这一组$p_{i}$和$q_{i}$的最长公共前缀长度,而如果已经(暴力枚举)确定了$l$、$a_{l}$以及$a_{l+1}$,那么问题即变为:

    选择一个长度为$l$且以1为开头、$a_{l}$为结尾的递减序列,并对$p_{a_{l+1}},p_{a_{l+1}+1},...,p_{n}$这个序列划分为$k-l$段,要求在每一段开头都小于$p_{a_{l}}$的基础上最小化字典序

    当$a_{l}$确定时,我们是希望$l$尽量大的,而这个$l$也就是最长下降子序列,$o(nlog n)$预处理出来

    更进一步的,在$l$和$a_{l}$确定后,我们希望$a_{l+1}$尽量大,考虑如何判定一个$a_{l+1}$是否合法,只需要满足:1.$p_{a_{l+1}}<p_{a_{l}}$;2.在$p_{a_{l+1}},p_{a_{l+1}+1},...,p_{n}$中存在$k-l$个数比$p_{a_{l}}$小

    更具体的,所谓$a_{l+1}$其实就是在$p_{n}$往前,第$k-l$个比$p_{a_{l}}$小的数,那么其之后(包括其自身)恰好存在$k-l$个比$p_{a_{l}}$小的数,必然以这些数为开头,即确定了划分的方案

    关于如何找到$a_{l+1}$,将1到$n$每一个数在$p_{i}$中的位置依次插入,插入时末尾第$k-l$小即为答案,用线段树维护并在其上二分即可

    找到$a_{l+1}$后,实际上这最后的$k-l$个数也可以看作$p_{a_{l+1}},p_{a_{l+1}+1},...,p_{n}$中最小的$k-l$个数,那么显然我们仍然可以在$a_{l+1}$最大的情况下找到最大的$l$即可

    总复杂度即$o(nlog n)$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 200005
     4 #define L (k<<1)
     5 #define R (L+1)
     6 #define mid (l+r>>1)
     7 int n,k,a[N],pos[N],dp[N],nex[N],b[N],f[N<<2];
     8 void update1(int k,int l,int r,int x,int y){
     9     if (l==r){
    10         f[k]=y;
    11         return;
    12     }
    13     if (x<=mid)update1(L,l,mid,x,y);
    14     else update1(R,mid+1,r,x,y);
    15     f[k]=max(f[L],f[R]);
    16 }
    17 int query1(int k,int l,int r,int x,int y){
    18     if ((l>y)||(x>r))return -0x3f3f3f3f;
    19     if ((x<=l)&&(r<=y))return f[k];
    20     return max(query1(L,l,mid,x,y),query1(R,mid+1,r,x,y));
    21 }
    22 void update2(int k,int l,int r,int x){
    23     f[k]++;
    24     if (l==r)return;
    25     if (x<=mid)update2(L,l,mid,x);
    26     else update2(R,mid+1,r,x);
    27 }
    28 int query2(int k,int l,int r,int x){
    29     if (l==r)return l;
    30     if (x<=f[R])return query2(R,mid+1,r,x);
    31     return query2(L,l,mid,x-f[R]);
    32 }
    33 int main(){
    34     scanf("%d%d",&n,&k);
    35     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    36     for(int i=1;i<=n;i++)pos[a[i]]=i;
    37     if (a[1]<=k){
    38         for(int i=k;i;i--){
    39             printf("%d ",i);
    40             for(int j=pos[i]+1;(j<=n)&&(a[j]>k);j++)printf("%d ",a[j]);
    41         }
    42         return 0;
    43     }
    44     memset(f,-0x3f,sizeof(f));
    45     for(int i=1;i<=n;i++){
    46         dp[i]=query1(1,1,n,a[i]+1,n)+1;
    47         if (a[i]<=a[1])dp[i]=max(dp[i],1);
    48         update1(1,1,n,a[i],dp[i]);
    49     }
    50     for(int i=1;i<=n;i++)
    51         if (dp[i]>=k){
    52             for(int j=1;j<=n;j++)printf("%d ",a[j]);
    53             return 0;
    54         }
    55     memset(f,0,sizeof(f));
    56     for(int i=1;i<=n;i++){
    57         nex[pos[i]]=query2(1,1,n,k-dp[pos[i]]);
    58         if (nex[pos[i]]<pos[i])nex[pos[i]]=0;
    59         update2(1,1,n,pos[i]);
    60     }
    61     for(int i=1;i<=n;i++)nex[0]=max(nex[0],nex[i]);
    62     for(int i=1;i<=n;i++)
    63         if (nex[i]==nex[0])dp[0]=max(dp[0],dp[i]);
    64     for(int i=1;i<nex[0];i++)printf("%d ",a[i]);
    65     for(int i=nex[0];i<=n;i++)b[i-nex[0]]=a[i];
    66     sort(b,b+n-nex[0]+1);
    67     for(int i=k-dp[0]-1;i>=0;i--){
    68         printf("%d ",b[i]);
    69         for(int j=pos[b[i]]+1;(j<=n)&&(a[j]>b[k-dp[0]-1]);j++)printf("%d ",a[j]);
    70     }
    71 } 
    View Code
  • 相关阅读:
    JavaScript周报#185
    让你跟上nodejs的资源
    微信服务号开发笔记
    Algs4-2.1.15昂贵的交换
    Algs4-2.1.14出列排序
    Algs4-2.1.13纸牌排序-按花色排序
    Algs4-2.1.12令希尔排序打印出递增序列的每个元素所带来的比较次数和数组大小的比值
    Algs4-2.1.10在希尔排序中为什么实现h有序时不使用选择排序?
    Algs4-2.1.11希尔排序序列改为存数组
    Algs4-2.1.9给出希尔排序的轨迹
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14586559.html
Copyright © 2011-2022 走看看