送礼物(LIS)
L I S LIS LIS保存的不是最长递增子序列,而是对应的 L I S LIS LIS长度的最小末尾元素。
比如 1 , 3 , 5 , 2 1,3,5,2 1,3,5,2 数组 d d d保存的就是 1 , 2 , 5 1,2,5 1,2,5,而 1 , 3 , 5 1,3,5 1,3,5才是 L I S LIS LIS.
若要求出 L I S LIS LIS序列还需要用一个数组 p o s pos pos,记录每个元素对应的 L I S LIS LIS长度。
并且这样求出来的 L I S LIS LIS对应的序号是按字典序最大排的。因为对于相同长度的 L I S LIS LIS的元素,后面会比之前先用到。
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
#define mst(a) memset(a,0,sizeof a)
int a[N],d[N],n,P,id[N],pos[N];
ll ans,len;
int main(){
scanf("%d%d",&n,&P);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
if(!len||a[i]>d[len]){
d[++len]=a[i];
pos[i]=len;
}
else {
int p=lower_bound(d+1,d+len+1,a[i])-d;
d[p]=a[i];
pos[i]=p;
}
}
int cnt=len;
for(int i=n;i>=1;i--){
if(pos[i]==cnt){
id[cnt--]=i;
ans+=a[i];
}
if(!cnt) break;
}
printf("%lld\n%d\n",ans+P,len);
for(int i=1;i<=len;i++) printf("%d\n",id[i]);
return 0;
}