hdu2890

//这题貌似只能用DC3构造法。因为N实在是太大了

//WA了很多发,蛋疼

//http://www.acmerblog.com/hdu-2890-longest-repeated-subsequence-4533.html

#include <iostream>
 #include <cstdio>
 #include <cmath>
 #include <algorithm>
 #include <cstring>
 using namespace std;
 const int maxn=50050;
 char str[maxn];
 int  s[maxn];
 int sa[maxn]; ///(你排第几)下标:排名情况, 数组值:首字符序号
 int rank[maxn];/// (排第几的是谁)  下标:首字符序号, 数组值:排名情况
 int height[maxn]; /// height[i]表示后缀i和后缀i-1的最长公共前缀
 int wa[maxn], wb[maxn], wv[maxn], wd[maxn];
 int x[maxn],  q[maxn];
 int pos;
 int cmp(int *r, int a, int b, int l)
 {
     return r[a]==r[b]&&r[a+l]==r[b+l];
 }

 void da(int *r, int n, int m){          ///  倍增算法 r为待匹配数组  n为总长度 m为字符范围
     int i, j, p, *x = wa, *y = wb, *t;
     for(i = 0; i < m; i ++) wd[i] = 0;
     for(i = 0; i < n; i ++) wd[x[i]=r[i]] ++;
     for(i = 1; i < m; i ++) wd[i] += wd[i-1];
     for(i = n-1; i >= 0; i --) sa[-- wd[x[i]]] = i;
     for(j = 1, p = 1; p < n; j *= 2, m = p){
         for(p = 0, i = n-j; i < n; i ++) y[p ++] = i;
         for(i = 0; i < n; i ++) if(sa[i] >= j) y[p ++] = sa[i] - j;
         for(i = 0; i < n; i ++) wv[i] = x[y[i]];
         for(i = 0; i < m; i ++) wd[i] = 0;
         for(i = 0; i < n; i ++) wd[wv[i]] ++;
         for(i = 1; i < m; i ++) wd[i] += wd[i-1];
         for(i = n-1; i >= 0; i --) sa[-- wd[wv[i]]] = y[i];
         for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i ++){
             x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1: p ++;
         }
     }
 }

 void calHeight(int *r, int n){           ///  求height数组。
     int i, j, k = 0;
     for(i = 1; i <= n; i ++) rank[sa[i]] = i;
     for(i = 0; i < n; height[rank[i ++]] = k){
         for(k ? k -- : 0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k ++);
     }
 }

 int find(int tmp, int n)
 {
     int l=0, r=n, mid;
     while(l<=r)
     {
         mid=(l+r)>>1;
         if(x[mid]==tmp) return mid;
         else if(x[mid]<tmp) l=mid+1;
         else r=mid-1;
     }
 }
 int flag;
 int judge(int mid,int rear,int k)
 {
     int cnt=1,i;
     std::sort(q,q+rear);
     int pre=q[0];
     for(i=1;i<rear;i++)
     {
         if(q[i]-pre>=mid)
           {
               cnt++;
               pre=q[i];
           }
     }
     return cnt>=k;
 }
 int check(int mid,int n,int k)
 {
     int i,rear=0;
     for(i=1;i<=n;i++)
     {
         if(height[i]<mid)
         {
             if(judge(mid,rear,k))
             {
                 flag=sa[i-1];
                 return 1;
             }
             q[0]=sa[i];
             rear=1;
         }
         else
            q[rear++]=sa[i];
     }
     if(judge(mid,rear,k))
     {
         flag=sa[i-1];
         return 1;
     }
     return 0;
 }
 int main()
 {
     int cas;
     scanf("%d",&cas);
     while(cas--)
     {
         int n,k;
         scanf("%d%d",&n,&k);
         int i;
         for(i=0;i<n;i++)
         {
             scanf("%d",&x[i]);
             s[i]=x[i];
         }
         std::sort(x,x+n);
         int ep=0;
         for(i=1;i<n;i++)
         {
             if(x[i]!=x[ep])
                x[++ep]=x[i];
         }
         for(i=0;i<n;i++)
            s[i]=find(s[i],ep)+2;
         s[n]=0;
         da(s,n+1,n+4);
         calHeight(s,n);
         int l=1,r=n,mid,ans;
         while(l<=r)
         {
             mid=(l+r)>>1;
             if(check(mid,n,k))
             {
                 l=mid+1;
                 ans=mid;
             }
             else
             {
                 r=mid-1;
             }
         }
         printf("%d\n",ans);
         for(i=flag;i<flag+ans;i++)
         {
             printf("%d\n",x[s[i]-2]);
         }
         if(cas)
            printf("\n");

     }
 }


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值