二路单调自增子序列模型【acdream 1216】

题目:acdream 1216 Beautiful
People

题意:每个人有两个值,能力值和潜力值,然后要求一个人的这两个值都严格大于第二个人的时候,这两个人才能呆在一块儿,给出许多人的值,求最多有多少个人?

分析:很容易想到是个单调非增模型,如果用O(n*n)的写法的话,会超时!

那么我们就要用二分优化来找。

我们可以先按第一个值 x 从小到大排序,然后按第二个值从大到小排序,这样的话找出的最长个数是没有错的。(想想为什么)

假如这样一个样例:

5

1 10

2 12

3 5

3 1

4 3

6 7

首先dp数组只有第一,二组样例:1 10 和2 12

然后第三个样例替换第一组:3 5 和 2 12  ,看看这组样例,发现不满足,但是他总的长度不会变,但是这样保存的话能保证后面出来的数能够最长。所以要想办法保存路径

然后第四组样例替换第三组:3 1 和 2 12

然后第5组样例替换第二组: 3 1  和 4 3 是不是满足条件了,而且最大值值变的更小了,

然后第六组样例加在后面:3 1 和 4 3 和 6 7 ,最大值

最后所有值的二分搜索的值为:1 2 1 1 2 3

那么发现保存路径也简单了。

然后从这个值里面输出一个递减的初始数组标号就可以了、

AC代码:

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 110000;
struct Node
{
    int x,y;
    int num,count;
};
Node a[N];
int cmp(Node a,Node b)
{
    if(a.x!=b.x)
        return a.x<b.x;
    if(a.y!=b.y)
        return a.y>b.y;
}
int dp[N],mark[N];

int Bin_Search(int l,int r,int x)
{
    while(l<=r)
    {
        int mid = (l+r)/2;   //假如要求相等的情况下,返回较小的值。
        if(dp[mid]==x)
            return mid;
        else if(dp[mid]<=x)
            l=mid+1;
        else
            r=mid-1;
    }
    return l;
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&a[i].x,&a[i].y);
            a[i].num=i;
        }
        sort(a+1,a+n+1,cmp);
        memset(dp,0x3f3f3f3f,sizeof(dp));
        int ans=0;
        int len = 1;
        for(int i=1;i<=n;i++)
        {
            int tmp=Bin_Search(1,len,a[i].y);           //lower_bound(dp+1,dp+1+n,a[i].y)-dp;
            if(tmp==len)
                len++;
            dp[tmp] = a[i].y;
            mark[i] = tmp;
            ans = max(ans,tmp);
        }
        printf("%d\n",ans);
        for(int i=n;i>=1;i--)
        {
            //printf("xx%d ",mark[i]);
            if(mark[i]==ans)
            {
                printf("%d",a[i].num);
                if(ans!=1)
                    printf(" ");
                ans--;
            }
        }
        printf("\n");
    }
    return 0;
}
时间: 2024-10-15 23:19:28

二路单调自增子序列模型【acdream 1216】的相关文章

最大上升子序列,最大下降子序列,最大非增子序列

For example,{1,5,2,4,3,5,6,4,7}的最大上升子序列是{1,2,3,5,6,7}长度为6 现已知原序列a[],如何求其最大上升子序列,最大下降子序列,最大非增子序列,最大非减子序列的长度?下面贴出两种方法:1.dp, 2.贪心+二分 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #defin

关于最长单调不升子序列和最长单调上升子序列写法

本人巨懒就用了STL lower_bound会找出序列中第一个大于等于x的数 upper_bound会找出序列中第一个大于x的数 对于N个数求最长单调不上升子序列,使用一个数组f[]存下 然后使用一个栈dq,存储不上升序列 把f中的每个元素挨个加到d里面 如果a[i] > d[len],在dq中找到第一个小于f[i]的数w,用f[i]代替 如果w在末尾,由于w < a[i],所以y后面能接的不如a[i]多,w让位给a[i]可以让序列更长 如果w不在末尾,那w本来就是死的,有什么挽救的必要吗(无

ACdream 1216 Beautiful People(二维上升子序列 O(nlogn))

Beautiful People Special Judge Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) Submit Statistic Next Problem Problem Description The most prestigious sports club in one city has exactly N members. Each of its members

ACdream 1216 (ASC训练1) Beautiful People(DP)

题目地址:http://acdream.info/problem?pid=1216 这题一开始用的是线段树,后来发现查询的时候还需要DP处理,挺麻烦..也就不了了之了..后来想到,这题其实就是一个二维的最长上升子序列.. 要先排序,先按左边的数为第一关键字进行升序排序,再按右边的数为第二关键字进行降序排序.这样的话,第一关键字相同的的肯定不在一个同一个上升子序列中.然后只对第二关键字进行复杂度为O(n*logn)的DP,找出最长上升序列,然后处理前驱,并输出即可. 代码如下: #include

POJ 1458 Common Subsequence-dp-(最长公共子序列模型)

题意:裸最长公共子序列 分析: 直接套用模型,注意初始化和实现的是细节 代码: #include<iostream> #include<string> #include<algorithm> #define max(a,b) a>b?a:b using namespace std; int dp[1010][1010]; string a,b; int main() { while(cin>>a>>b){ for(int i=0;i<

最长上升子序列模型

1017. 怪盗基德的滑翔翼 怪盗基德是一个充满传奇色彩的怪盗,专门以珠宝为目标的超级盗窃犯. 而他最为突出的地方,就是他每次都能逃脱中村警部的重重围堵,而这也很大程度上是多亏了他随身携带的便于操作的滑翔翼. 有一天,怪盗基德像往常一样偷走了一颗珍贵的钻石,不料却被柯南小朋友识破了伪装,而他的滑翔翼的动力装置也被柯南踢出的足球破坏了. 不得已,怪盗基德只能操作受损的滑翔翼逃脱. 假设城市中一共有N幢建筑排成一条线,每幢建筑的高度各不相同. 初始时,怪盗基德可以在任何一幢建筑的顶端. 他可以选择一

!HDU 1513 Palindrome--dp--(最长公共子序列模型)

题意:给定一个字符序列,求最少添加多少个字符能让它变成对称序列 分析:这题的做法竟然是把序列颠倒之后求最长公共子序列,然后n-dp[n][n]就是答案.记住这种做法. 在这里再说一次最长公共子序列的做法:dp[i][j]表示序列1的前i个字符和序列2的前j个字符比较时的最长公共子序列的长度,状态转移公式:1.当a[i]==b[j]时,dp[i][j]=dp[i-1][j-1]+1:2.否则,dp[i][j]=max(dp[i-1][j],dp[i][j-1]) 代码: #include<iost

ACdream 1216——Beautiful People——————【二维LIS,nlogn处理】

Beautiful People Special Judge Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) Submit Statistic Next Problem Problem Description The most prestigious sports club in one city has exactly N members. Each of its members

九度OJ-1112-导弹拦截-最长不增子序列

题目1112:拦截导弹 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:5218 解决:2603 题目描述: 某国为了防御敌国的导弹袭击,开发出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹来袭,并观测到导弹依次飞来的高度,请计算这套系统最多能拦截多少导弹.拦截来袭导弹时,必须按来袭导弹袭击的时间顺序,不允许先拦截后面的导弹,再拦截前面的导弹. 输入: 每组输入有两行, 第一行