I - Beautiful People
##題意:
給出 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;
}