做01背包做到的这个LIS,常见的n2会超时,所以才有nlogn可行
先来介绍一下n2
dp[i] 表示该序列以a[i]为结尾的最长上升子序列的长度
所以第一层循环循环数组a,第二层循环循环第i个元素前面的元素,里面做一个基本升序判断,然后找最大值
定义一个外部变量记录最大值
nlogn
用了一个数组进行维护对于每一个新加入的数,如果比这个数组中的所有元素都大,那么该数加入数组,如果有比这个数大的,则用该数替换第一个比他大的数
奈何这个题最坑的地方是输出!
#include <iostream> #include <cstdio> #include <string.h> #include <algorithm> #include <cmath> using namespace std; const int maxn = 5e5 + 5e3; int dp[maxn],dp_idx; struct node{ int p,r; }data[maxn]; bool cmp(node a,node b) { return a.p < b.p; } int get_idx(int left,int right,int num) { while(left <= right) { int mid = (left + right) >> 1; if(dp[mid] > num)right = mid - 1; else left = mid + 1; } return right+1; } int main() { int n; int cas = 1; while(~scanf("%d",&n)) { for(int i = 0;i < n;i++) scanf("%d%d",&data[i].p,&data[i].r); //sort(data,data+n,cmp);不用排序,将无序的存储到有序的数组里就可以 // for(int i = 0;i < n;i++) // printf("%d %d ",data[i].p,data[i].r); memset(dp,0,sizeof(dp)); dp[0] = data[0].r; dp_idx = 0; for(int i = 1;i < n;i++) { if(data[i].r > dp[dp_idx]) { dp[++dp_idx] = data[i].r; } else { int idx = get_idx(0,dp_idx,data[i].r); //cout<<"idx = "<<idx<<endl; dp[idx] = data[i].r; } } // for(int i = 0;i <= dp_idx;i++) // { // printf("%d ",dp[i]); // } printf("Case %d: My king, at most %d ",cas++,dp_idx+1); if(dp_idx+1 > 1) printf("roads can be built. "); else printf("road can be built. "); } return 0; }