牛客網暑期ACM多校訓練營(第五場)H subseq(樹狀陣列)
阿新 • • 發佈:2018-11-10
題意
給定一個序列 a[1..n],求下標字典序第 k 小的嚴格遞增子序列
題解
考慮逐位確定,每次計算 a[i…n] 中,以a[i]這個數字為開頭的嚴格遞增子序列的個數,用樹狀陣列統計,然後1…n與k比較,小於k就減去dp[i],否則就放a[i],當然要保證a[i]大於前一個放的數;這個樹狀陣列和以前的不太一樣,是記錄大於等於x的數量,與一般的是倒過來的,雖然有些意外不過想了想確實是,以前的是記在區間的右端點,現在是記錄在左端點
程式碼
#include<bits/stdc++.h> #define N 1000005 #define P pair<int,int> using namespace std; typedef long long ll; const int M=1e9+7; const int inf=1e9+7; ll c[N],dp[N]; int b[N],ans[N],a[N]; void add(int x,ll k,int n) { while(x){ c[x]+=k; if(c[x]>1e18)c[x]=1e18; x-=(x&-x); } } ll sum(int x,int n) { ll ans=0; while(x<=n){ ans+=c[x]; x+=(x&-x); if(ans>1e18)ans=1e18; } return ans; } int main() { int n; ll k; scanf("%d%lld",&n,&k); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); b[i]=a[i]; } sort(b+1,b+n+1); int tot=unique(b+1,b+n+1)-b; for(int i=n;i;i--){ a[i]=lower_bound(b+1,b+tot,a[i])-b; ll tmp=sum(a[i]+1,tot); dp[i]=tmp+1; add(a[i],tmp+1,tot); } int p=0; for(int i=1;i<=n&&k;i++){ if(p&&a[i]<=a[ans[p]])continue; if(k>dp[i])k-=dp[i]; else ans[++p]=i,k--; } if(!p||k)printf("-1\n"); else { printf("%d\n%d",p,ans[1]); for(int i=2;i<=p;i++) printf(" %d",ans[i]); puts(""); } return 0; }