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