题解:SP11469 SUBSET - Balanced Cow Subsets
双倍经验:P3067。
题意简述
给定长度为
思路
对于一个数
- 它在
集合。 - 它在
集合。 - 它不在任何一个集合中。
所以如果我们暴搜复杂度是
我们只好使用折半搜索将时间复杂度降到
如何折半搜索?
首先我们将序列分成
我们首先证明一个等式:设
则
证明:由题意可得
对于
对于
写出代码:
map<long long,int>mp;
void dfs1(int now,long long sum){
if(now==n/2+1){
mp[sum]++;
return;
}
dfs1(now+1,sum);
dfs1(now+1,sum+a[now]);
dfs1(now+1,sum-a[now]);
}
long long ans;
void dfs2(int now,long long sum){
if(now==n+1){
if(sum!=0)ans+=mp[sum];//0不能统计
return;
}
dfs2(now+1,sum);
dfs2(now+1,sum-a[now]);
dfs2(now+1,sum+a[now]);
}
但是这个代码是错误的。
对于序列
我们将
显然这个代码会重复统计。
所以我们要用一个二进制数,存储每个点是否被选。
AC Code
#include<bits/stdc++.h>
using namespace std;
int n,a[25];
map<int,vector<int> >mp;
void dfs1(int now,long long sum,int S){
if(now==n/2+1){
mp[sum].push_back(S);
return;
}
dfs1(now+1,sum,S);
dfs1(now+1,sum+a[now],S|(1<<(now-1)));
dfs1(now+1,sum-a[now],S|(1<<(now-1)));
}
long long ans;
bool b[1048577];
void dfs2(int now,long long sum,int S){
if(now==n+1){
if(mp.count(sum)){
for(int S2:mp[sum]){
if(b[S+S2]==0)ans++;
b[S+S2]=1;
// printf("%d\n",S+S2);
}
}
return;
}
dfs2(now+1,sum,S);
dfs2(now+1,sum-a[now],S|(1<<(now-1)));
dfs2(now+1,sum+a[now],S|(1<<(now-1)));
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
dfs1(1,0,0);
dfs2(n/2+1,0,0);
printf("%d",(ans-1));
return 0;
}
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】