1. 程式人生 > >Newcoder 143 H.subseq(BIT)

Newcoder 143 H.subseq(BIT)

Description

給出一個長度為nn的序列a1,...,ana_1,...,a_n,定義序列b1,...,bmb_1,...,b_m是好的當且僅當以下條件成立:

1.1bin,1im1\le b_i\le n,1\le i\le m

2.bi<bi+1,1i<mb_i<b_{i+1},1\le i<m

3.abi<abi+1,1i<ma_{b_i}<a_{b_{i+1}},1\le i<m

求所有好的bb序列中字典序第kk小的

Input

第一行輸入兩個整數n,kn,k,之後輸入nn個整數a1,...,ana_1,...,a_n

(1n5105,1k1018,1ai109)(1\le n\le 5\cdot 10^5,1\le k\le 10^{18},1\le a_i\le10^9)

Output

輸出字典序第kk小的好的bb序列,無解則輸出1-1

Sample Input

3 2 1 2 3

Sample Output

2 1 2

Solution

dp[i]dp[i]表示以ii開頭的滿足條件的bb序列個數,那麼有dp[i]=1+i<j,ai<ajdp[j]dp[i]=1+\sum\limits_{i<j,a_i<a_j}dp[j],用樹狀陣列維護dp[i]dp[i]的值,從後往前轉移,每次把dp[i]dp[i]根據aia_i的值插入樹狀陣列中,即可O(nlogn)O(nlogn)得到dpdp序列

之後從前往後考慮字典序第kk小的bb

序列,假設第一位放11,那麼有dp[1]dp[1]種方案數,若kdp[1]k\le dp[1],說明第一位確實是11,進而考慮第二位的取值(注意:1.每次考慮當前位的取值必然要大於已經確定的前一位取值;2.由於確定完當前位後,後面的取值有空和非空兩種情況,此時要將kk減一來去掉後面為空的情況,減完後若kk00說明後面確實為空,否則繼續考慮後面位的取值),若k>dp[1]k>dp[1],說明第一位不是11,那麼k=kdp[1]k=k-dp[1],表示有dp[1]dp[1]種字典序小的方案已經考慮了,下面考慮其他值放在第一位,以此類推,若考慮完所有元素kk仍然非00則無解,否則已經確定的序列即為答案,時間複雜度O(n)O(n)

Code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
ll INF=2e18;
#define maxn 500005
struct BIT 
{
	#define lowbit(x) (x&(-x))
	ll b[maxn],n;
	void init(int _n)
	{
		n=_n;
		for(int i=1;i<=n;i++)b[i]=0;
	}
	void update(int x,ll v)
	{
		while(x<=n)
		{
			b[x]+=v;
			b[x]=min(b[x],INF);
			x+=lowbit(x);
		}
	}
	ll query(int x)
	{
		ll ans=0;
		while(x)
		{
			ans+=b[x];
			ans=min(ans,INF);
			x-=lowbit(x);
		}
		return ans;
	}
}bit;
int n,a[maxn],h[maxn];
ll k,dp[maxn];
vector<int>ans;
int main()
{
	scanf("%d%lld",&n,&k);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		h[i-1]=a[i];
	}
	sort(h,h+n);
	int m=unique(h,h+n)-h;
	bit.init(m);
	for(int i=n;i>=1;i--)
	{
		a[i]=m+1-(lower_bound(h,h+m,a[i])-h+1);
		dp[i]=bit.query(a[i]-1)+1;
		dp[i]=min(dp[i],INF);
		bit.update(a[i],dp[i]);
	}
	for(int i=1;i<=n;i++)
	{
		if(ans.size()>0&&a[i]>=a[ans[ans.size()-1]])continue;
		if(k==0)break;
		if(dp[i]>=k)
		{
			ans.push_back(i);
			k--;
		}
		else k-=dp[i];
	}
	if(k)printf("-1\n");
	else
	{
		printf("%d\n",ans.size());
		for(int i=0;i<ans.size();i++)
			printf("%d%c",ans[i],i==ans.size()-1?'\n':' ');
	}
	return 0;
}