zoukankan      html  css  js  c++  java
  • 【HDU2890 Longest Repeated subsequence】 后缀数组之重复k次最长子序列(不可覆盖)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2890

    题目大意:给你一个含n个数的序列,再给你一个k,让你求最少重复k次的最长子序列(子序列不能重叠)。

    解题思路:先吐槽一下,题意不明,蛋疼许久。 

    我可以这么理解 : 1、保证子序列重复次数cnt大于k的前提下,len为一个子序列长度,然后最长子序列最长,即cnt*len最大。

                              2、保证子序列重复次数cnt大于k的前提下,只需让子序列长度len最长即可。

    我在理解1中挣扎了许久才发现我题目都理解错了,题目意思是理解2,擦擦擦。

              这题X值很大,先离散化处理一下。 以前写过一道最少重复k次子序列可相互覆盖的题目,这题是不可覆盖。所以这里要特殊处理一下,开始我用标记,后来发现处理的时候还是有点问题,后来改成贪心做,即多开一个que数组,记录sa[]值,每次遇见height<mid(枚举的长度)时,对que中序列排序一下,这样就保证了处理的时候就是从左往右了。

    View Code
      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cmath>
      4 #include <algorithm>
      5 #include <cstring>
      6 using namespace std;
      7 const int maxn=50050;
      8 char str[maxn];
      9 int  num[maxn];
     10 int sa[maxn]; ///(你排第几)下标:排名情况, 数组值:首字符序号
     11 int rank[maxn];/// (排第几的是谁)  下标:首字符序号, 数组值:排名情况
     12 int height[maxn]; /// height[i]表示后缀i和后缀i-1的最长公共前缀
     13 int wa[maxn], wb[maxn], wv[maxn], wd[maxn];
     14 int X[maxn],  que[maxn];
     15 int pos;
     16 
     17 
     18 int cmp(int *r, int a, int b, int l)
     19 {
     20     return r[a]==r[b]&&r[a+l]==r[b+l];
     21 }
     22 
     23 void da(int *r, int n, int m){          ///  倍增算法 r为待匹配数组  n为总长度 m为字符范围
     24     int i, j, p, *x = wa, *y = wb, *t;
     25     for(i = 0; i < m; i ++) wd[i] = 0;
     26     for(i = 0; i < n; i ++) wd[x[i]=r[i]] ++;
     27     for(i = 1; i < m; i ++) wd[i] += wd[i-1];
     28     for(i = n-1; i >= 0; i --) sa[-- wd[x[i]]] = i;
     29     for(j = 1, p = 1; p < n; j *= 2, m = p){
     30         for(p = 0, i = n-j; i < n; i ++) y[p ++] = i;
     31         for(i = 0; i < n; i ++) if(sa[i] >= j) y[p ++] = sa[i] - j;
     32         for(i = 0; i < n; i ++) wv[i] = x[y[i]];
     33         for(i = 0; i < m; i ++) wd[i] = 0;
     34         for(i = 0; i < n; i ++) wd[wv[i]] ++;
     35         for(i = 1; i < m; i ++) wd[i] += wd[i-1];
     36         for(i = n-1; i >= 0; i --) sa[-- wd[wv[i]]] = y[i];
     37         for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i ++){
     38             x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1: p ++;
     39         }
     40     }
     41 }
     42 
     43 void calHeight(int *r, int n){           ///  求height数组。
     44     int i, j, k = 0;
     45     for(i = 1; i <= n; i ++) rank[sa[i]] = i;
     46     for(i = 0; i < n; height[rank[i ++]] = k){
     47         for(k ? k -- : 0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k ++);
     48     }
     49 }
     50 
     51 int find(int tmp, int n)
     52 {
     53     int l=0, r=n, mid;
     54     while(l<=r)
     55     {
     56         mid=(l+r)>>1;
     57         if(X[mid]==tmp) return mid;
     58         else if(X[mid]<tmp) l=mid+1;
     59         else r=mid-1;
     60     }
     61 }
     62 
     63 bool judge(int mid, int rear, int k)
     64 {
     65     sort(que,que+rear);
     66     int pre=que[0], cnt=1;
     67     for(int i=1; i<rear; i++)
     68         if(que[i]-pre>=mid) pre=que[i], cnt++;
     69     return cnt>=k;
     70 }
     71 
     72 bool check(int mid, int n, int k)
     73 {
     74     int rear=0;
     75     for(int i=1; i<=n; i++)
     76     {
     77         if(height[i]<mid)
     78         {
     79             if(judge(mid,rear,k))
     80             {
     81                 pos=sa[i-1];
     82                 return true;
     83             }
     84             rear=0, que[rear++]=sa[i];
     85         }
     86         else que[rear++]=sa[i];
     87     }
     88     if(judge(mid,rear,k))
     89     {
     90         pos=sa[n-1];
     91         return true;
     92     }
     93     return false;
     94 }
     95 
     96 int main()
     97 {
     98     int n, k, T;
     99     cin >> T;
    100     while(T--)
    101     {
    102         scanf("%d%d",&n,&k);
    103         for(int i=0; i<n; i++) scanf("%d",num+i), X[i]=num[i];
    104         sort(X,X+n);
    105         int ep=0;
    106         for(int i=1; i<n; i++)
    107             if(X[i]!=X[ep]) X[++ep]=X[i];
    108         for(int i=0; i<n; i++)
    109             num[i]=find(num[i],ep)+2;
    110         num[n]=0;
    111         da(num,n+1,n+5);
    112         calHeight(num,n);
    113         int l=1, r=n, mid, ans=0;
    114         while(l<=r)
    115         {
    116             mid=(l+r)>>1;
    117             if(check(mid,n,k))
    118             {
    119                 l=mid+1;
    120                 ans=mid;
    121             }
    122             else r=mid-1;
    123         }
    124         printf("%d\n",ans);
    125         for(int i=pos; i<pos+ans; i++) printf("%d\n",X[num[i]-2]);
    126         if(T) puts("");
    127     }
    128     return 0;
    129 }
  • 相关阅读:
    [BZOJ3530][SDOI2014]数数
    [Luogu3121][USACO15FEB]审查Censoring
    [BZOJ1212][HNOI2004]L语言
    [Luogu3041][USACO12JAN]视频游戏的连击Video Game Combos
    AC自动机总结
    (三)LDAP 新增用户
    (二) LDAP 安装
    (一)LDAP 简介
    (十三)VMware Harbor 身份验证模式
    loj#2541. 「PKUWC2018」猎人杀
  • 原文地址:https://www.cnblogs.com/kane0526/p/3033924.html
Copyright © 2011-2022 走看看