如题:http://poj.org/problem?id=1631
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 11636 | Accepted: 6348 |
Description

A typical situation is schematically depicted in figure 1. The ports of the two functional blocks are numbered from 1 to p, from top to bottom. The signal mapping is described by a permutation of the numbers 1 to p in the form of a list of p unique numbers in the range 1 to p, in which the i:th number specifies which port on the right side should be connected to the i:th port on the left side.Two signals cross if and only if the straight lines connecting the two ports of each pair do.
Input
Output
Sample Input
4 6 4 2 6 3 1 5 10 2 3 4 5 6 7 8 9 10 1 8 8 7 6 5 4 3 2 1 9 5 8 9 2 3 1 7 4 6
Sample Output
3 9 1 4
Source
思路:求最长上升子序列的dp。容易想到的一般解法dp[i]表示前i个的最长子序列的长度。dp[i]=max(dp[j])+1。其中满足a[j]<a[i].
复杂度为O(n*n);题目中n为40000.超时。于是看到一种O(nlogn)的解法。
dp[i]:表示所有的长度为i的上升子序列中的最后一个元素的最小值。
因此首先dp[i]所有的值赋值为INF。对于每一个a[i],在dp数组中寻找第一个》=a[i]的位置,将a[i]插入。这样复杂度为O(n*n),但是注意到dp数组肯定是单调递增。因此二分搜索每一个a[i].最终复杂度降为O(nlogn).
注意:这里的序列最后求出来是严格递增,而不是非递减。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXP 40005
#define INF 0x0fffffff
int a[MAXP];
int dp[MAXP];
int main()
{
// freopen("C:\\1.txt","r",stdin);
int n;
cin>>n;
while(n--)
{
int p;
cin>>p;
int i;
for(i=0;i<p;i++)
{
int x;
cin>>x;
a[i]=x;
dp[i]=INF;
}
for(i=0;i<p;i++)
{
*lower_bound(dp,dp+p,a[i])=a[i];
}
int res=0;
for(i=0;i<p;i++)
{
if(dp[i]==INF)
break;
res++;
}
cout<<res<<endl;
}
return 0;
}