PKU 1743 Musical Theme

 

题目要求最长不重叠的长度相同的子串长度,使得对应的差为定值。

先用后缀数组求出h数组(h[i] = LCP(i-1,i) (LCP是最长公共前缀)),但由于这题目要求子串间不能重叠,因此采用二分答案的方法,根据排序好的相邻后缀的关系,比较它们之间的距离差是否大于答案即可。

下面程序中RMQ部分没有调用,本题不需此内容。

 

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <math.h>
  4. #define max(a,b) (a>b?a:b)
  5. const int N = 20100; 
  6. const int INF = 1<<30;
  7. int n;
  8. int s[N];
  9. int cnt[N], mem[4][N], *rank, *nrank, *sa, *nsa, h[N]; 
  10. int d[N][30];
  11. void radix_sort() 
  12.     int i, k; 
  13.     rank = mem[0]; 
  14.     nrank = mem[1]; 
  15.     sa = mem[2]; 
  16.     nsa = mem[3]; 
  17.     memset( cnt, 0, sizeof(cnt));
  18.     memset( mem, 0, sizeof(mem));
  19.     for(i = 0; i < n; i++) cnt[s[i]]++; 
  20.     for(i = 1; i < 200; i++) cnt[i] += cnt[i-1]; 
  21.     for(i = n-1; i >= 0; i--) sa[--cnt[s[i]]] = i; 
  22.     for(rank[0]=0, i=1; i < n; i++) 
  23.     { 
  24.         rank[sa[i]] = rank[sa[i-1]]; 
  25.         if(s[sa[i]]!=s[sa[i-1]]) rank[sa[i]]++; 
  26.     } 
  27.     for(k = 1; k<n && rank[sa[n-1]] < n-1; k*=2) 
  28.     { 
  29.         for(i = 0; i < n; i++) cnt[rank[sa[i]]] = i+1; 
  30.         for(i = n-1; i >= 0; i--) 
  31.         {
  32.             if(sa[i]-k>=0) 
  33.                 nsa[--cnt[rank[sa[i]-k]]] = sa[i]-k; 
  34.         }
  35.         for(i = n-k; i < n; i++) 
  36.             nsa[--cnt[rank[i]]] = i; 
  37. /*//
  38.         for ( i=0; i<n; i++ )
  39.             printf("%d ", nsa[i] );
  40.         printf("/n" );
  41. /*/
  42.         for(nrank[nsa[0]]=0, i=1; i < n; i++) 
  43.         { 
  44.             nrank[nsa[i]] = nrank[nsa[i-1]]; 
  45.             if(rank[nsa[i]] != rank[nsa[i-1]] 
  46.             || rank[nsa[i]+k] != rank[nsa[i-1]+k]) 
  47.                 nrank[nsa[i]]++; 
  48.         } 
  49.         int *stemp = rank; rank = nrank; nrank = stemp;
  50.         stemp = sa; sa = nsa; nsa = stemp;
  51.     } 
  52. void initRMQ( int *D, int top)
  53. {
  54.     int i , j ,k,sk;
  55.     for( i = 0 ; i < top ; i ++ )
  56.         d[i][0] = i;
  57.     for( j = 1 ,k=2; k <= top ; j ++,k <<= 1 )
  58.     {
  59.         for( i = 0 ; i < top ; i ++ )
  60.         {
  61.             sk = i+(k>>1) ;
  62.             d[i][j] = d[i][j-1] ;
  63.             if( sk < top && D[d[i][j]] >= D[d[sk][j-1]] ) 
  64.                 d[i][j] = d[sk][j-1] ;
  65.         }       
  66.     }
  67. }
  68. int RMQ( int *D , int i , int j )
  69. {
  70.     //int k = log22[j-i+1] ;
  71.     int k = int(log(j-i+1.0)/log(2.0)) ;
  72.     int k2 = (1 << k)-1;
  73.     if( D[d[i][k]] < D[d[j-k2][k]] )
  74.         return d[i][k];
  75.     else
  76.         return d[j-k2][k];
  77. }
  78. void get_lcp_rmq() 
  79.     int i, j, k; 
  80.     memset( h, 0, sizeof(h));
  81.     for (j = 0, i = 0; i < n; i++)
  82.     {
  83.         if (rank[i] == 0) 
  84.             h[0] = j = 0;
  85.         else
  86.         {
  87.             k = sa[rank[i]-1];
  88.             for (j = max(j-1,0); s[i+j] == s[k+j]; j++);
  89.             h[rank[i]] = j;
  90.         }
  91.     }
  92. //  initRMQ( h, n );
  93. int check( int x )
  94. {
  95.     int i;
  96.     int min = n, max = 0;
  97.     int tmp;
  98.     for ( i=1; i<n; i++ )
  99.     {
  100.         if ( h[i]<x ) 
  101.         {
  102.             min = n;
  103.             max = 0;
  104.         }
  105.         else
  106.         {
  107.             int ta = sa[i-1];
  108.             int tb = sa[i];
  109.             if ( ta>tb )
  110.             {
  111.                 tmp = ta;               
  112.                 ta = tb;
  113.                 tb = tmp;
  114.             }
  115.             if ( ta<min ) 
  116.                 min = ta;
  117.             if ( tb>max )
  118.                 max = tb;
  119.             if ( max-min>x )
  120.                 return 1;
  121.         }
  122.     }
  123.     return 0;
  124. }
  125. int main ()
  126. {
  127.     int i;
  128.     while ( scanf("%d", &n)!=EOF && n!=0 )
  129.     {
  130.         int pre, now;
  131.         scanf("%d", &pre );
  132.         for ( i=0; i<n-1; i++ )
  133.         {
  134.             scanf("%d", &now );
  135.             s[i] = now-pre+100;
  136.             pre = now;
  137.         }
  138.         s[n-1] = -INF;
  139.         radix_sort();
  140.         get_lcp_rmq();
  141.         int l = 0, r = n/2+1;
  142.         while ( l<r-1 )
  143.         {
  144.             int mid = (l+r)/2;
  145.             if ( check(mid) )
  146.                 l = mid;
  147.             else
  148.                 r = mid;
  149.         }
  150.         if ( check(r) && r>=4 )
  151.             printf("%d/n", r+1 );
  152.         else if ( check(l) && l>=4 )
  153.             printf("%d/n", l+1 );
  154.         else
  155.             printf("0/n");
  156.     }
  157.     return 0;
  158. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值