题目链接:http://acdream.info/problem?pid=1216
题意:
一个俱乐部有n个人, 每个人都有一个漂亮值和财富值。现在俱乐部要举办活动, 但是俱乐部中有些人是相互讨厌, 相互讨厌的人有两累即si<=sj&&bi>=bj or si>=sj&&bi<=bj ;参加活动的人不能相互讨厌。 问最多能有多少人参加活动, 并把参加活动的人输出来。
分析:
很明显, 满足条件的人si, bi都是严格的单调的。 所以我们可以想到最长单调子序列, 这个就是多了一个条件的限制。我们可以先一个限制条件si从小到大排, 相同的bi一从大到小排;这样我们就可以按另一个限制条件bi求最长单调递增, 最后打印路径。相信有很多人不明白另一个限制条件bi要按从大到小排。我给出一个样例看了之后想想就明白了, 这里太不好描述了。
9
1 3
2 5
4 1
4 2
4 3
4 4
5 5
6 6
最长长度为3,
AC代码:
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cctype>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
const int maxn = 1e6 + 10;
const int inf = 0x3f3f3f3f;
int dp[maxn];
int x[maxn];
struct Info
{
int x, y, id;
bool operator < (const Info& rhs) const
{
if(x == rhs.x)
return y > rhs.y;
return x < rhs.x;
}
} a[maxn];
int search_id(int k, int len)
{
int l = 0, r = len, m;
while(l < r)
{
m = (l + r)/2;
if(k == x[m])
return m;
else if(k < x[m])
r = m;
else
l = m + 1;
}
return l;
}
int main()
{
int n, len = 0;
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%d%d", &a[i].y, &a[i].x);
a[i].id = i+1;
}
sort(a, a+n);
a[n].x = a[n].y = inf;
x[len++] = a[0].y;
for(int i = 1; i < n; i++)
{
x[len] = inf;
int j = search_id(a[i].y, len);
if(j == len)
len++;
x[j] = a[i].y;
dp[i] = j;
}
printf("%d\n", len);
int ok = 1, j = n, k = len-1;
for(int i = n-1; i >= 0; i--)
{
if(k>=0 && dp[i]==k && a[i].x<a[j].x && a[i].y<a[j].y)
{
k--;
j = i;
if(ok == 1)
{
printf("%d", a[i].id);
ok = 0;
}
else
printf(" %d", a[i].id);
}
}
puts("");
return 0;
}