2019牛客多校第九场 D-Knapsack Cryptosystem 【折半查找】

本文分享了一道来自牛客网的算法题解决方案,通过折半查找和状态压缩技巧,将大规模数据处理问题转化为可接受的小规模问题。利用二进制串表示数据取舍,通过map映射状态和数据和的关系,再结合set集合存储和比较,实现高效求解。

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

题目来源:https://ac.nowcoder.com/acm/contest/889/D
在这里插入图片描述
在这里插入图片描述
★枯了,爆零场。不过我真的没写过 折半查找 的题 ,我还在那里疯狂dfs剪枝


思路:

这题的数据范围是 36,236已经非常大了,时空都承受不了
但是如果把它砍成两半来处理,每一半只有218 这样的数据就比较好接受了
我们可以用一个 二进制串 表示数据的取舍 比如 010010 就是表示取了第二、五个 ,而这又是独一无二的10进制数(称状态
用一个map映射 状态 和 这个状态所取数的和 的关系 map<LL,int> mp
以及一个 set集合 存储这个和
然后就可以比较好的处理这个问题了
详细见代码~

代码:

#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<deque>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=40;
const int sz=1<<36;
const int inf=2e9;
const int mod=1e9+7;
const double pi=acos(-1);
typedef long long LL;
LL n,m;
LL f[maxn];
bool vis[maxn];
set<LL> s;
map<LL,int> mp;
template<class T>
inline void read(T &x)
{
    char c;x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
int main()
{
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++) read(f[i]);
    int p=n/2,q=n-p;
    for(int i=0;i<(1<<p);i++){                     //找到前一半的状态和 数据和 的关系 并保存出现过的数据和
        LL sum=0;
        for(int j=0;j<p;j++) if(i&(1<<j)) sum+=f[j+1];
        s.insert(sum);
        mp[sum]=i;
    }                          
    for(int i=0;i<(1<<q);i++){                    //另一半
        LL sum=0;
        for(int j=1;j<=q;j++) if(i&(1<<j-1)) sum+=f[p+j];
        if(s.count(m-sum)){
            for(int j=1;j<=p;j++)
                if(mp[m-sum]&(1<<j-1)) vis[j]=1;
                else vis[j]=0;
            for(int j=1;j<=q;j++)
                if(i&(1<<j-1)) vis[j+p]=1;
                else vis[j+p]=0;
            break;
        }
    }
    for(int i=1;i<=n;i++) cout<<vis[i];
    printf("\n");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值