最长上升子序列NLOGN算法

 http://boj.me/onlinejudge/showproblem.php?problem_id=1836

Description
Comic Board是个神奇的地方,宽阔的AC河笔直地穿过这片土地。Comic
Board有N个国家(编号从1至N),每个国家在河两岸各有7座城池,象征着七色的彩虹。城市沿着河岸一字排开,构成了一幅美丽而壮阔的山水长卷。
现在Comic Board的众国家准备联合在河上建彩虹桥,以便游客能更好地欣赏AC河。由于跨国建桥将涉及到国境线与护照等问题,因此他们只打算在两岸相同国家的城市间建桥。为了发展旅游业,他们希望建尽量多的桥来吸引游客。现在,他们把任务交给了Chirlley国的首席工程师车裂。你能帮她算出最多能建多少座彩虹桥吗?


Input
多组数据。
第一行为正整数T(0 < T < 10),表示有T组数据。
对于每组数据:
第一行为一个整数N(0 < N <= 10000),表示有N个国家。
第二行,第三行为7N个从1至N的整数,分别表示两岸的城市所属的国家。


Output
对于每组数据,输出一行,即最多能建造的彩虹桥的数目。

Sample Input

2
2
1 2 2 2 2 1 2 1 2 1 2 1 1 1
2 1 2 1 2 2 2 1 1 2 1 1 2 1
3
3 1 1 3 1 3 3 1 2 2 1 2 1 1 2 2 2 3 3 3 2
1 3 3 1 1 3 3 1 1 2 3 3 3 1 1 2 2 2 2 2 2


Sample Output

11
14

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef int(*Array8)[8];
Array8 p[700001];

int T;
int N;
int len[100001];
int f[100001][8];


int bsearch(int low,int high,int key)
{
  while(low <= high)
  {
    int mid = (low+high)/2;
    if(len[mid] > key) high = mid -1;
    else if(len[mid] < key)
      low = mid +1;
    else
        return mid;
  } 
   return high;
}


int DP()
{
  int top =1; 
  memset(len,7*N+1,(7*N+1)*sizeof(int));
  len[0] = 0;
  len[1] = (*p[1])[7];
  int max = -1;
  for(int i=1;i<=7*N;i++) //nlogn算法
  {
       
       for(int j=7;j>=1;j--)
      {
        if((*p[i])[j] > len[top])
        {
          top++;
          len[top] = (*p[i])[j];
          if(max < top) max = top;
        } 
        else if((*p[i])[j] < len[top])
        {
          int xiabiao = bsearch(1,top,(*p[i])[j]);
          if(len[xiabiao] != (*p[i])[j]&& len[xiabiao+1] >(*p[i])[j])
          {
            len[xiabiao+1] = (*p[i])[j];
            if(max < xiabiao+1) max = xiabiao+1;
          }
        }
        else
        continue;
      }
  
  }

  return max;
}
int main()
{
  cin>>T;
  while(T--)
  {
    scanf("%d",&N);
    int temp;
    memset(f,0,sizeof(f));
    for(int i=1;i<=7*N;i++)
    {
       scanf("%d",&temp);
       for(int j=1;j<=7;j++)
         if(f[temp][j]==0)
         {
           f[temp][j] = i; // 桥,下面国家对上面国家
           break;
         }
    }
   
    for(int i=1;i<=7*N;i++)
    {
        scanf("%d",&temp);
        p[i] = &f[temp];

    }

    cout<<DP()<<endl;     
  }    
    
  return 0;    
} 




#include <iostream> 
using namespace std;
const int MinValue = -9999999;
//在上升的序列array[]找到最大的i,使得 array[i]<=key ,
//找到返回这个i,找不到返回0,s=1,从1开始 
int bisearch(int s,int e,int key,int * array)
{
    if(s > e) return -1;
    while(s < e -1)
    {
      int mid = s +(e-s)/2;
      if(key <= array[mid]) //使整个 区间 往 左移 
        e = mid ;
      else  
        s = mid ;        
    }
    
    if(array[e] <= key )
    return e;     
    else if(array[s]<= key)
    return s;
    else
    return 0;
    
}

int LIS(int* array ,int N)
{
  //单调递增 序列 
  int* len_min = new int[N+1];//  长度为i的 最长上升子序列中,结尾数字 的最小值 
  memset(len_min,0,(N+1)*sizeof(int));
  len_min[1] = array[0];
  len_min[0] = MinValue; //设置长度为0时,结尾数字为最小 
  int len = 1;//len_min数组的长度,
  //也是以 i 结尾的序列中,最长上升子序列的长度的最大值 
  for(int i=1;i<N;i++)
  {
    //找到 比array[i]小的 最大的数的下标, 返回至少为0 
    int xiaBiao =bisearch(1,len,array[i],len_min);       
    //目前最长的上升子序列 
    if(len_min[xiaBiao+1]==0)
    {
      len++;
    }
    //更新 长度为 xiaBiao+1的上升序列的,结尾数字的最小值   
    len_min[xiaBiao+1] = array[i];        
  }
  
  for(int i=0;i<N+1;i++)
  cout<<len_min[i]<<" ";
  cout<<endl;
   
  delete []len_min;
  len_min = 0; 
  return len; 
}


int main()
{
    int array[] = {1,9,2,10,6,7,3,4,5,8}; 
    int N = sizeof(array)/sizeof(int);
    int cnt =  LIS(array , N);
    cout<<cnt<<endl; 
    system("pause");
    return 0;
}


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值