最长上升子序列NLOGN算法

来源:互联网 发布:热血无赖优化 编辑:程序博客网 时间:2024/05/22 04:48

 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;}


 

原创粉丝点击