第k小子集和[双指针+meet in the middle]

本文探讨了如何解决一个特定的算法问题:给定一个长度不超过35的序列,求其所有子集和中第k小的数值。通过将问题分解为两个子数组的组合,并使用二分查找来确定目标值的方法,文章详细阐述了解决方案的实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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

可以二分第 \(k\) 小的数是多少(假设是 \(X\) ,转化为判定性问题 我二分的是 \(\leq X\) 的数对数量是否 \(<k\)

ORZ GNAQ

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, "\ntime:%.5fms", clock() * 1000.0 / CLOCKS_PER_SEC);
#endif
  return 0;
}

转载于:https://www.cnblogs.com/storz/p/10466221.html

P3067 [USACO12OPEN] Balanced Cow Subsets G 提交答案加入题单复制题目 提交 22.24k 通过 5.69k 时间限制 1.00s 内存限制 125.00MB 复制 Markdown 中文 折叠 进入 IDE 模式 题目描述 我们定义一个奶牛集合 S 是平衡的,当且仅当满足以下两个条件: S 非空。 S 可以被划分成两个集合 A,B,满足 A 里的奶牛产奶量之等于 B 里的奶牛产奶量之。划分的含义是,A∪B=S 且 A∩B=∅。 现在给定大小为 n 的奶牛集合 S,询问它有多少个子集是平衡的。请注意,奶牛之间是互不相同的,但是它们的产奶量可能出现相同。 输入格式 第一行一个整数 n,表示奶牛的数目。 第 2 至 n+1 行,每行一个数 a i ​ ,表示每头奶牛的产奶量。 输出格式 输出一个数表示方案总数。 样例解释 共存在三种方案。集合 {1,2,3} 可以划分为 {1,2} 与 {3};集合 {1,3,4} 可以划分为 {1,3} 与 {4};集合 {1,2,3,4} 可以划分为 {1,4} 与 {2,3},共 3 种子集。 显示翻译 题意翻译 输入输出样例 输入 #1复制 4 1 2 3 4 输出 #1复制 3 说明/提示 对于全部数据,保证 1≤n≤20,1≤a i ​ ≤10 8 。 我的代码如下,请检查 #include <bits/stdc++.h> using namespace std; using ll = long long; const int N = 25; ll n; ll a[N], sum, ans; void dfs (ll k, ll tot) { if (k == n + 1) { if (tot == sum - tot) ans ++; return; } dfs (k + 1, tot + a[k]); dfs (k + 1, tot); } int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n; for (int i = 1; i <= n; i ++) cin >> a[i], sum += a[i]; dfs(1, 0); cout << ans << '\n'; return 0; }
最新发布
07-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值