题目大意:
本质上就是对于贫穷城市p需要匹配富裕城市r, 用a[p] = r表示之后不难发现就是求数列a[ i ]的最长不降子序列
由于不会出现两个贫穷城市匹配同一个富裕城市故相当于求最长上升子列
如果用传统的O(n^2)的方法求将会超时
这里用dp[ i ]表示长度为 i 的子列的结尾最小是dp[ i ] 那么,显然dp[ i ] 满足单调递增
初始化dp[1] = a[1]
考虑没下一个数 a[ i ], 对于当前找到的最长长度len, 从dp[1 到 len ] 中找到a[ i ] 可以放的位置,如果a[ i ] > dp[len] 那么len++; dp[len] = a[ i ];
否则对于 dp[ ii ] < a[ i ] < dp[ ii + 1 ] 更新dp[ ii + 1 ] 为 a[ i ]即可这样一直持续到 a[n],由于每次二分查找dp[1 ~ len]中对应的位置, 时间复杂度为O(n*logn)
代码如下:
Result : Accepted Memory : 560 KB Time : 140 ms
/*
* Author: Gatevin
* Created Time: 2014/8/9 19:26:09
* File Name: hehe.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define maxn 500000
int a[maxn + 10];
int dp[maxn + 10];
int n;
int len, mid;
int main()
{
int cnt = 0;
while(~scanf("%d", &n))
{
cnt++;
int ta,tb;
for(int i = 1; i <= n; i++)
{
scanf("%d %d", &ta, &tb);
a[ta] = tb;
}
dp[1] = a[1];
len = 1;
int l,r,mid;
for(int i = 2; i <= n; i++)
{
l = 1;
r = len;
while(l <= r)
{
mid = (l + r) / 2;
if(dp[mid] < a[i])
{
l = mid + 1;
}
else
{
r = mid - 1;
}
}
dp[l] = a[i];
if(l > len) len = l;
}
printf("Case %d:\n", cnt);
printf("My king, at most %d %s can be built.\n\n", len, len == 1 ? "road" : "roads");
}
return 0;
}