送礼物(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;
}