zoukankan      html  css  js  c++  java
  • 第k小子集和[双指针+meet in the middle]

    给出一个长度 (nleq 35) 的序列,求他的子集和的第 (k)

    把前 n/2 的子集和放到一个数组里 后 n/2 的放到另一个数组里,然后问题转化为了求各取一个数和的第 (k)

    可以二分第 (k) 小的数是多少

    namespace QvvQ {
    vll t1, t2;
    int n, a[50];
    ll k;
    void dfs(int pos, int r, ll sum, vll &s) {
      if (pos > r) return void(s.pb(sum));
      dfs(pos + 1, r, sum + a[pos], s), dfs(pos + 1, r, sum, s);
    }
    void init() {
    
    } 
    
    bool check(ll X) {//leq X 的数对的数量是否<k
      ll cnt = 0;
      for (int p1 = 0, p2 = t2.size() - 1; p1 != t1.size(); ++p1) {
        while (p2 > 0 && t1[p1] + t2[p2] > X) --p2;
        if (t1[p1] + t2[p2] <= X) cnt += p2 + 1;
        if (cnt >= k) return 0;
      }
      return 1;
    }
    
    void solve() {
      n = in, k = in;
      lo1(i, n) in, a[i];
      dfs(1, n >> 1, 0, t1), dfs(n / 2 + 1, n, 0, t2);
      sort(all(t1)), sort(all(t2));
      ll l = 1, r = t1.back() + t2.back();
      while (l <= r) {
        if (check(mid)) l = mid + 1;
        else r = mid - 1;
      }
      out, l;//l-1+1 l-1是最后一个合法(<k)的
    } 
     
    }
    
    int main() {
    #ifdef QvvQ
      // freopen("data.in", "r", stdin);
      // freopen("data.out", "w", stdout);
      Dbg = 1;
    #endif
      int T = 1;
      while (T--) QvvQ::init(), QvvQ::solve();
    #ifdef QvvQ
      fprintf(stderr, "
    time:%.5fms", clock() * 1000.0 / CLOCKS_PER_SEC);
    #endif
      return 0;
    }
    
  • 相关阅读:
    无熟人难办事?—迪米特法则
    考题抄错会做也白搭—模板方法模式
    简历复印—原型模式
    Android Studio 安装及常见问题
    雷锋依然在人间——工厂方法模式
    欢迎测试
    客户端程序设计V1
    Linux服务器端程序设计V1
    【Alpha】最后一篇
    【Alpha】开发日志Day10-0721
  • 原文地址:https://www.cnblogs.com/storz/p/10466221.html
Copyright © 2011-2022 走看看