CodeForces Optimal Subsequences (Hard Version)

題目鏈接:傳送門

題意簡述 

這道題有兩個版本,簡單版本只需要簡單的模擬就可以了。困難版則是將數據量加大到2E5的級別。所以需要提高代碼的執行效率才能通過。

題目給定一個長度爲N的序列,目的是求出符合以下要求的子序列:

  1. 長度爲K
  2. 子序列元素總和最大
  3. 子序列在符合上面的條件的同時需要字典序最小

題目的考察方式是給定K和一個Pos,要求你返回長度爲K的上述子序列中第pos個元素。並且給定的(K,pos)對的數量級也是2E5。

題意分析

通過題意可以看出對代碼的執行效率要求比較高。N^2的複雜度顯然過不了。所以我們將目標轉向NlogN。然後整個解題思路如下:

  1. 貪心構造出子序列
  2. 找出長度爲K的子序列的第pos個元素

題目的查詢的數量級比較大,並且每個查詢的長度K和pos也不一定是按一定的大小順序給出。所以我們需要離線所有的查詢,並且將查詢按照某種順序排列好,比如按K的大小從大到小排列好, 這樣我們首先構造出最小的子序列,後面的序列可以在前面的基礎上添加一定的元素構造出來。

這時又遇到一個問題,我們很容易想到利用貪心思想將原始序列按一定的規則排序後可以很簡單的構造出符合要求的特定長度的的子序列,但是我們對構造出來的子元素無法做到隨機訪問(個人認爲實現這個目標所執行的步驟已經超時了),而順序訪問顯然會超時。所以我們需要在這個找第pos個元素上花功夫。也就是減少該步驟的複雜度。

解題方法

我採用的方法是利用樹狀數組來加速查詢的操作,具體看代碼:

我利用樹狀數組維護信息是:爲構造子序列,我從前i個原始序列元素中選取的元素的數量,記爲S[i]。維護了這個信息之後,如果我想詢問第pos個元素是哪個,只需要二分查詢出滿足S[i]==pos的最小i即可。則第i個原始元素便是子序列第pos個元素。

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <algorithm>
#include <map>
#include <set>
#include <stack>
#include <math.h>
#include <queue>
#include <string>
#include <sstream>
#include <vector>
#include <string.h>
#include <time.h>
using namespace std;
 
const int maxn = 2e5 + 5;
const int INF = 1e9;
 
struct Data{
    int a,idx;
 
    bool operator < (const Data & b) const{
        return a == b.a ? idx < b.idx : a > b.a;
    }
} d[maxn];
 
struct Query{
    int k,pos,idx;
 
    bool operator < (const Query & b) const{
        return k < b.k;
    }
}q[maxn];
 
 
int res[maxn];
 
int n;
 
inline int lowbit(int x){
    return x&(-x);
}
 
int C[maxn];
int b[maxn];
 
inline void update(int idx, int v){
    for(;idx <= n; idx+= lowbit(idx)){
        C[idx] += v;
    }
}
 
 
inline int query(int idx){
    int sum = 0;
    for(; idx; idx -= lowbit(idx)){
        sum += C[idx];
    }
    return sum;
}
 
inline int solve() {
 
    memset(C, 0, sizeof(C));
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%d", &d[i].a);
        d[i].idx = i;
        b[i] = d[i].a;
    }
    sort(d+1, d+1+n);
    int m;
    scanf("%d", &m);
    for(int i = 0; i < m; i++){
        scanf("%d %d", &q[i].k,&q[i].pos);
        q[i].idx = i;
    }
    sort(q, q+m);
    int curL = 1;
    for(int i = 0; i < m; i++){
        for(; curL <= q[i].k; curL++){
            update(d[curL].idx, 1);
        }
        int l = 1, r = n;
        while(l < r){
            int mid = l + r >> 1;
            if(query(mid) >= q[i].pos){
                r = mid;
            }else{
                l = mid + 1;
            }
        }
        res[q[i].idx] = b[l];
    }
    for(int i = 0; i < m; i++){
        printf("%d\n", res[i]);
    }
 
    return 0;
}
 
 
int main() {
    int t = 1;
#ifndef ONLINE_JUDGE
    freopen("1.in", "r", stdin);
//    freopen("1.out", "w", stdout);
    int mao = clock();
    scanf("%d", &t);
#endif
    while(t--) {
        solve();
    }
#ifndef ONLINE_JUDGE
    cerr << "Time:" << clock() - mao << "ms" << endl;
#endif
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章