1 条题解
-
0
自动搬运
来自洛谷,原作者为

ivyjiao
复活了搬运于
2025-08-24 22:46:38,当前版本为作者最后更新于2023-04-30 10:55:17,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
upd on 2025/7/20:攻克了 hack 数据,申请再次通过。
已在文末给出最新代码。
https://www.luogu.com.cn/record/225727835
题意简(?)述:
经过上一次惨痛的经历后,郝哥痛改前非,不再卖生瓜蛋子,秤也没有了吸铁石。然而刘华强并不打算放过他。
有一个人再来买瓜。
郝哥望着那辆熟悉的摩托车,没等华强发话,便喊道:“ 块钱一斤!没有大棚瓜!保熟!”
“给我挑亿个!”
郝哥刚转过身,看个架子上 个分别重 斤的瓜,刚想挑瓜,华强又说:“今天我要请宋大哥吃答辩,得买 斤西瓜,你这瓜保够吗?”
郝哥明白,华强又来找茬了。
华强拿起了上次他劈西瓜和郝哥的刀,对郝哥说:“你这瓜要是管够我肯定要啊,那它要是不够怎么办啊?”
郝哥知道,华强刀功了得,他可以把任何瓜劈成完全等重的两份,不过每个瓜只劈一刀,尽管华强可以以很短的时间劈开一个瓜(),不过他不想白费力气,他想让郝哥在 之内告诉他最少需要劈几个瓜,否则就要劈了郝哥。
郝哥不想再被劈一刀,所以他找到了你。
如果郝哥无论如何都会被劈(没有任何一种可行方案能让华强买到他想要重量的瓜)。输出
-1。part one:
直接爆搜加一个人人都会的剪枝就行了,时间复杂度 。
#include<iostream> using namespace std; int n,a[31],ans=114514; long long m; void LHQ(int G,int P,int J,long long sum){ if(sum>m) return; if(G>n){ //cout<<sum<<endl; if(sum==m) ans=min(ans,J); return; } if(P==0) sum+=a[G]*2; else if(P==1) sum+=a[G],J++; for(int i=0;i<3;i++) LHQ(G+1,i,J,sum); } int main(){ cin>>n>>m; m*=2; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=0;i<3;i++) LHQ(1,i,0,0); cout<<ans; }这个怎么样?

………外卖……萨日朗……郝哥萨日朗……
part two:
考虑折半搜索,时间复杂度 。
#include<iostream> #include<unordered_map> using namespace std; int n,N,a[31],ans=114514; long long m; unordered_map <int,int> PII; void LHQ(int G,int P,int J,long long sum){ if(sum>m) return; if(sum==m){ PII[sum]=J; return; } if(G==N+1){ if(sum<=m) PII[sum]=J; return; } if(P==0) sum+=a[G]*2; else if(P==1) sum+=a[G],J++; for(int i=0;i<3;i++) LHQ(G+1,i,J,sum); } void HG(int G,int P,int J,long long sum){ if(sum>m) return; if(sum==m){ ans=min(ans,PII[sum]+J); return; } if(G==n+1){ //cout<<sum<<endl; if(sum<=m&&PII.count(m-sum)) ans=min(ans,PII[m-sum]+J); return; } if(P==0) sum+=a[G]*2; else if(P==1) sum+=a[G],J++; for(int i=0;i<3;i++) HG(G+1,i,J,sum); } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cin>>n>>m; N=n/2; m*=2; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=0;i<3;i++) LHQ(1,i,0,0); for(int i=0;i<3;i++) HG(N+1,i,0,0); if(ans>100000) cout<<-1; else cout<<ans; }这个怎么样?

………外卖……萨日朗……郝哥萨日朗……
part three:
时间复杂度肯定是没假的,不可能比这更低了。
考虑剪枝优化。
最优性剪枝:当现在劈瓜的个数已经比目前最优的个数多了,就不用再继续搜下去了。
#include<iostream> #include<unordered_map> using namespace std; int n,N,a[31],ans=114514; long long m; unordered_map <int,int> PII; void LHQ(int G,int P,int J,long long sum){ if(sum>m) return; if(sum==m){ PII[sum]=J; return; } if(G==N+1){ if(sum<=m) PII[sum]=J; return; } if(P==0) sum+=a[G]*2; else if(P==1) sum+=a[G],J++; for(int i=0;i<3;i++) LHQ(G+1,i,J,sum); } void HG(int G,int P,int J,long long sum){ if(sum>m||J>ans) return; if(sum==m){ ans=min(ans,PII[sum]+J); return; } if(G==n+1){ //cout<<sum<<endl; if(sum<=m&&PII.count(m-sum)) ans=min(ans,PII[m-sum]+J); return; } if(P==0) sum+=a[G]*2; else if(P==1) sum+=a[G],J++; for(int i=0;i<3;i++) HG(G+1,i,J,sum); } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); cin>>n>>m; N=n/2; m*=2; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=0;i<3;i++) LHQ(1,i,0,0); for(int i=0;i<3;i++) HG(N+1,i,0,0); if(ans==114514) cout<<-1; else cout<<ans; }这个怎么样?

………外卖……萨日朗……郝哥萨日朗……
part four:
很明显不能再进一步剪枝了,我们考虑其它的优化。
优化搜索顺序:把 数组进行排序后再搜索。
减少传参:容易发现当前搜索的这个瓜是否被劈不重要,只关心最后总共劈几个就行。
预处理:对 数组进行一个后缀和,方便判断超过下界的无解情况。
调整
块长折半的长度:这个需要注意一下调完的长度可能会 或 ,需要避免。卡时:这个不用我多说了吧!
#include<bits/stdc++.h> using namespace std; int n,N,ans=114514,m,a[32],b[32],cnt; unordered_map <int,int> PII; void LHQ(int G,int J,int sum){ cnt++; if(cnt>7e6) return; if(sum>m) return; if(G==N+1){ if(PII[sum]) PII[sum]=min(PII[sum],J+1); else PII[sum]=J+1; return; } LHQ(G+1,J,sum+a[G]); LHQ(G+1,J+1,sum+a[G]/2); LHQ(G+1,J,sum); } void HG(int G,int J,int sum){ cnt++; if(cnt>1.5e7){ cout<<ans<<endl; return; } if(sum>m||J>ans) return; if(sum==m){ ans=min(ans,PII[sum]+J); return; } if(G==n+1){ if(PII[m-sum]) ans=min(ans,J+PII[m-sum]-1); return; } HG(G+1,J,sum+a[G]); HG(G+1,J+1,sum+a[G]/2); HG(G+1,J,sum); } int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n>>m; N=n/2; m*=2; for(int i=1;i<=n;i++) cin>>a[i],a[i]*=2; sort(a+1,a+1+n); LHQ(1,0,0); HG(N+1,0,0); if(ans==114514) cout<<-1; else cout<<ans; }这个怎么样?

满意了吧?
part five:

What's up,
你是故意找茬是不是?你要不要吧!你瞅瞅现在哪有瓜?
大棚。
#include<bits/stdc++.h> #include<bits/extc++.h> using namespace std; using namespace __gnu_pbds; int n,N,ans=114514,m,a[32],cnt; long long b[32]; cc_hash_table <int,int> PII; void LHQ(int G,int J,int sum){ if(sum>m) return; if(sum+b[G]<m) return; if(sum==m){ PII[sum]=J; return; } if(G==N+1){ if(PII[sum]) PII[sum]=min(PII[sum],J+1); else PII[sum]=J+1; return; } LHQ(G+1,J,sum+a[G]); LHQ(G+1,J+1,sum+a[G]/2); LHQ(G+1,J,sum); } void HG(int G,int J,int sum){ if(sum>m||J>ans) return; if(sum==m){ ans=min(ans,PII[sum]+J); return; } if(G==n+1){ if(PII[m-sum]) ans=min(ans,J+PII[m-sum]-1); return; } HG(G+1,J,sum+a[G]); HG(G+1,J+1,sum+a[G]/2); HG(G+1,J,sum); } int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n>>m; N=min(n/2+1,n-2); m*=2; for(int i=1;i<=n;i++) cin>>a[i],a[i]*=2; sort(a+1,a+1+n); for(int i=n;i>=1;i--) b[i]=b[i+1]+a[i]; LHQ(1,0,0); HG(N+1,0,0); if(ans==114514) cout<<-1; else cout<<ans; }这个怎么样?

满意了吧?
写在最后:
这题从我第一次提交到第一次 AC 共提交了 次。
upd: 次,被 hack 了就不算 AC。
感谢
https://www.luogu.com.cn/user/355192的一些帮助。
最新代码:
#include<bits/stdc++.h> #include<bits/extc++.h> #define int long long using namespace std; using namespace __gnu_pbds; int n,N,ans=114514,m,a[32],cnt,b[32]; cc_hash_table <int,int> PII; void LHQ(int G,int J,int sum){ if(sum>m) return; if(sum+b[G]<m) return; if(sum==m){ PII[sum]=J; return; } if(G==N+1){ if(PII[sum]) PII[sum]=min(PII[sum],J+1); else PII[sum]=J+1; return; } LHQ(G+1,J,sum+a[G]); LHQ(G+1,J+1,sum+a[G]/2); LHQ(G+1,J,sum); } void HG(int G,int J,int sum){ if(sum>m||J>ans) return; if(sum==m){ ans=min(ans,PII[sum]+J); return; } if(G==n+1){ if(PII[m-sum]) ans=min(ans,J+PII[m-sum]-1); return; } HG(G+1,J,sum+a[G]); HG(G+1,J+1,sum+a[G]/2); HG(G+1,J,sum); } signed main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n>>m; N=min(n/2+1,n-2); m*=2; for(int i=1;i<=n;i++) cin>>a[i],a[i]*=2; sort(a+1,a+1+n); for(int i=n;i>=1;i--) b[i]=b[i+1]+a[i]; LHQ(1,0,0); HG(N+1,0,0); if(ans==114514) cout<<-1; else cout<<ans; }
- 1
信息
- ID
- 8669
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者