【问题背景】
zhx 给他的妹子们排序。
【问题描述】
zhx有N个妹子,他对第i个妹子的好感度为ai, 且所有ai两两不相等。现在N个妹子随意站成一
排,他要将她们根据好感度从小到大排序。 他使用的是冒泡排序算法。如果排序过程中
好感度为ai的妹子和好感度为aj的妹子发生了交换, 那么她们之间会发生一场口角。
现在 zhx 想知道, 给定妹子的初始排列, 在排序完成后, 最多存在多少个妹子, 她们任意两
人之间没发生过口角。
正式地, 考虑对数组ai进行冒泡排序, 如果ai和aj在排序过程中发生交换,那么在两个元素之
间连一条边。你需要求出,排序结束后,最多存在多少个元素,其中任意两个元素之间不存在连边。
【输入格式】
第一行两个整数 N, 表示妹子数量。
接下来一行 N 个整数ai,表示初始第 i 个妹子的好感度。
【输出格式】
一行一个整数, 表示最多满足要求的妹子的个数。
【样例输入】
3
3 1 2
【样例输出】
2
【样例解释】
{1, 2}。
【数据规模与约定】
对于30%的数据, 1 ≤n≤ 16。
对于70%的数据, 1 ≤n≤ 5000。
对于100%的数据, 1 ≤n≤ 100000, 0 ≤ai<n。
(当时看到实在不会做啊,还是QTY_YTQ神说这就是求最长上升子序列长度,好劲啊)
就是i和j两个妹子不交换,当且仅当ai<aj,所以只要求最长上升子序列长度就行了。
(然而当时我只会n2算法70分,QTY_YTQ神写了个线段树维护A了,%%%)
正解是nlogn的最长上升子序列:
1 program sort(input,output); 2 const 3 inf=123456789; 4 var 5 a,f,c:array[0..100010]of longint; 6 i,k,n:longint; 7 function min(a,b:longint):longint; 8 begin 9 if a<b then exit(a) else exit(b); 10 end; 11 function find(x:longint):longint; 12 var 13 l,r,mid:longint; 14 begin 15 if x<c[1] then exit(0); 16 l:=1;r:=k; 17 while l<r-1 do 18 begin 19 mid:=(l+r)>>1; 20 if c[mid]>x then r:=mid-1 else l:=mid; 21 end; 22 if c[r]<x then exit(r) else exit(l); 23 end; 24 begin 25 assign(input,'sort.in');assign(output,'sort.out');reset(input);rewrite(output); 26 readln(n); 27 for i:=1 to n do read(a[i]); 28 for i:=1 to n do c[i]:=inf; 29 k:=0; 30 for i:=1 to n do begin f[i]:=find(a[i])+1;if c[f[i]]=inf then inc(k);c[f[i]]:=min(c[f[i]],a[i]); end; 31 write(k); 32 close(input);close(output); 33 end.