bitset + meet in the middle,P3067 [USACO12OPEN] Balanced Cow Subsets G

目录

一、题目

1、题目描述

2、输入输出

2.1输入

2.2输出

3、原题链接

二、解题报告

1、思路分析

2、复杂度

3、代码详解


一、题目

1、题目描述

编辑

2、输入输出

2.1输入

编辑

2.2输出

编辑

3、原题链接

https://www.luogu.com.cn/problem/P3067


二、解题报告

1、思路分析

洛谷题解区要么就是 O(3^n) 的错误做法,要么就是 O(6^{n / 2}) 的做法

这里给一种比较稳的做法

考虑一个平衡子集 S,它可以被分为4部分:

  1. s1:在 a 的前半部分中属于A 的集合

  2. s2:在 a 的前半部分中属于B 的集合

  3. s3:在 a 的后半部分中属于A 的集合

  4. s4:在 a 的后半部分中属于B 的集合

那么一个合法子集一定满足:s1 + s3 = s2 + s4 => s1 - s2 = s4 - s3

那么我们折半枚举前后两部分所有子集的 sum|A'| - sum|B'|

对于前半部分,我们枚举所有子集,保存所有 <sum|A'| - sum|B'|, msk> 这样的二元数对(其中msk为选择的下标集合),然后按照第一维排序并按照二元数对去重

然后按 第一维分组,用bitset 合并msk,保存在列表 st中

对于后半部分,我们枚举子集s,计算出sum|A'| - sum|B'|后,在st中二分得到对应的msk,和子集s的bitset合并

对于后半部分的子集s,其 bitset 中1的个数就是前半部分和s合并后是平衡子集的合法子集个数

值得注意的是,我们折半枚举子集的时候把空集也包含上,这样计算出来的答案会多1,输出的时候减去即可。

2、复杂度

时间复杂度: O(3 ^ {n/2} * (log(3^{n/2}) + 2^{n/2} / 64))空间复杂度:O(3^{n / 2} * 32)

3、代码详解

复制代码
  
cpp 复制代码
#include <bits/stdc++.h>
namespace ranges = std::ranges;
namespace views = std::views;
using i64 = long long;
using u32 = unsigned;
using u64 = unsigned long long;

constexpr int B = 1024;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n;
    std::cin >> n;
    const int U = 1 << (n / 2);
    std::vector<int> a(n / 2), b(n - n / 2), sum(U);
    for (int i = 0; i < n / 2; ++i) {
        std::cin >> a[i];        
        sum[1 << i] = a[i];
    }
    for (int i = 0; i < n - n / 2; ++i) {
        std::cin >> b[i];
    }

    std::vector<std::array<int, 2>> p;
    for (int s = 0; s < U; ++s) {
        if (s > 0) sum[s] = sum[s & (s - 1)] + sum[s & -s]; 
        p.push_back({sum[s], s});
        for (int t = s; t > 0; t = (t - 1) & s) {
            p.push_back({sum[s] - sum[t] * 2, s});
        }
    }
    ranges::sort(p);
    p.resize(std::unique(p.begin(), p.end()) - p.begin());
    
    std::vector<std::pair<int, std::bitset<B>>> st;
    for (int i = 0, j = 0; i < p.size(); i = j) {
        std::bitset<B> msk;
        while (j < p.size() && p[i][0] == p[j][0]) {
            msk.set(p[j++][1]);
        }
        st.push_back({p[i][0], msk});
    }

    const int V = 1 << b.size();
    std::vector<std::bitset<B>> good(V); 
    std::vector<int> nsum(V);
    for (int i = 0; i < b.size(); ++i) {
        nsum[1 << i] = b[i];
    }
    
    for (int s = 0; s < V; ++s) {
        if (s > 0) nsum[s] = nsum[s & (s - 1)] + nsum[s & -s];
        
        int target = nsum[s]; 
        auto it = ranges::lower_bound(st, target, {}, [](auto &x) {
            return x.first;
        });
        if (it != st.end() && it->first == target) {
            good[s] |= it->second;
        }
        
        for (int t = s; t > 0; t = (t - 1) & s) {
            target = nsum[s] - nsum[t] * 2; 
            it = ranges::lower_bound(st, target, {}, [](auto &x) {
                return x.first;
            });
            if (it != st.end() && it->first == target) {
                good[s] |= it->second;
            }
        }
    }

    int ans = 0;
    for (auto &bt : good) {
        ans += bt.count();
    }   
    
    std::cout << ans - 1 << '\n';

    return 0;
}
相关推荐
北域码匠4 小时前
高通滤波算法深度解析(High-Pass Filter)
stm32·算法·c#·数字信号处理·嵌入式开发·滤波算法·高通滤波
指掀涛澜天下惊4 小时前
强化学习进阶篇八 策略梯度算法
深度学习·学习·算法·强化学习
乌萨奇也要立志学C++4 小时前
【洛谷】kmp算法
开发语言·算法
禹凕4 小时前
Dijkstra算法详解与应用
python·算法
YaraMemo5 小时前
元启发式算法框架
人工智能·算法·5g·信息与通信·启发式算法·信号处理
weixin_307779135 小时前
一维无粘 Burgers 方程的激波形成问题:MacCormack 格式求解
c++·算法·matlab
HugoStudio_SWAN6 小时前
洛谷 B4500 / B4449 / B3843 凯撒密码、密码强度与密码合规——加密与安全的三道门
c++·学习·程序人生·算法·安全
枫叶林FYL7 小时前
【群体智能集群控制工程实践】第3章 一致性协同算法
算法
禹凕7 小时前
滑动窗口算法实战指南
python·算法
DisonTangor7 小时前
【腾讯混元雪耻归来】 Hy4 preview:770B 参数 MoE 旗舰模型,1M 上下文全面开源
人工智能·算法·开源·aigc·腾讯云·腾讯云ai代码助手