I - Beautiful People(元組嚴格單調遞增最大長度 nlogn)

I - Beautiful People

ZOJ - 2319

##題意:

​ 給出 m 個人,每個人有兩個屬性:強壯度(s),美麗度(b),如果a的s,b中任意一個屬性大於等於y的對應屬性,另一個屬性小於y,兩個人就會打架。現在要辦一個party,要求邀請儘可能多的人,並且他們不能打架。輸出人數和每個人的編號(編號從1開始)

思路:

​ 這道題不難想象邀請最多的人 滿足他們的S,B序列都是嚴格遞增的。那麼我們只要從所有人的S,B序列中找出所有的嚴格遞增的個數中的最多的即可。

​ 我們將所有人按照S從小到大排序,如果S相同 就讓B大的排在前面,然後找出S的最長嚴格遞增子序列即可,並記錄路徑即可。(這樣的話可以保證我們選取過程中S相同 的所有B中,B最多選一個)

​ 題目中的數據爲

m:4

S: 1 1 2 2

B: 1 2 1 2

我們按規定排序後

S: 1 1 2 2

B: 2 1 2 1

我們選取排序後的第二個人和第四個人即可

#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e5+100;
struct Data
{
    int a,b,id;
} data[maxn];
bool operator <(const Data &aa,const Data &bb)
{
    if(aa.a==bb.a)
        return aa.b>bb.b;
    return aa.a<bb.a;
}
int S[maxn],pre[maxn],dp[maxn],lcsid[maxn];
vector<int> V;
int main()
{
    int t,fa=0;
    scanf("%d",&t);
    while(t--)
    {
        if(fa) puts("");
        fa=1;
        int n;
        scanf("%d",&n);
        for(int i=1; i<=n; ++i)
        {
            scanf("%d%d",&data[i].a,&data[i].b);
            data[i].id=i;
        }
        sort(data+1,data+n+1);
        for(int i=1; i<=n; ++i) S[i]=data[i].b;
        int len=0;
        mset(pre,-1);
        dp[0]=-1;
        lcsid[0]=-1;
        for(int i=1; i<=n; ++i)
        {
            int th=lower_bound(dp,dp+len+1,S[i])-dp;//th就是該元素該插入的位置,且他從上一個地方過來
            pre[i]=lcsid[th-1];
            lcsid[th]=i;
            dp[th]=S[i];
            len=max(len,th);
        }//pre[lcsid[len]]一直王回溯即可
        V.clear();
        for(int v=lcsid[len]; v!=-1; v=pre[v])
            V.push_back(v);
        printf("%d\n",V.size());
        for(int i=0; i<V.size(); ++i)
            printf("%d ",data[V[i]].id);
        puts("");
    }

    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章