[ABC184F] Programming Contest题解
前置知识
meet in middle (折半搜索)
会的大佬请跳过
不会的请自己前往oi wiki或CSDN(百度吧,少年)
解题思路
纯暴力
看完题目考虑将每一种情况计算出来,排序后找不超过T的最大值
因为每个数有(选/不选)两种情况
所以总共2^n种结果
显而易见,时间复杂度 O(2^n)
n=40时,显然会G
正解
引出
暴力思路告诉我们,现在需要一种优秀的算法(奇技淫巧)来帮助我们
从庞大的信竞知识中,我们找到了折半搜索;
步骤
- 将数据分成2组,1到n/2一组,n/2+1到n为一组
- 每组单独算情况,存在数组中
- 两个结果数组单独排序(升序)
- a指针从第一组结果数组的第一个元素,b指针从第二组结果数组的最后一个元素(没学过指针怎么办?变量模拟即可,详见代码)
- 如果两个元素之和大于T,b--
- 否则用元素之和更新答案(正确性显然,自己思考)
AC代码
#include <bits/stdc++.h> using namespace std; long long n,t,mx,sz[42],a[1050000],b[1050000],tota,totb; void dfs(int qd,int zd,int lim,long long zhi) { if(qd>zd)return ; if(zhi+sz[qd]>t) { dfs(qd+1,zd,lim,zhi); return; } if(lim==1)a[++tota]=zhi+sz[qd]; else b[++totb]=zhi+sz[qd]; dfs(qd+1,zd,lim,zhi); dfs(qd+1,zd,lim,zhi+sz[qd]); return; } int main() { scanf("%lld%lld",&n,&t); for(int i=1;i<=n;i++) { scanf("%lld",&sz[i]); } dfs(1,n/2,1,0); dfs(n/2+1,n,2,0); sort(a+1,a+tota+1); sort(b+1,b+totb+1); int zz=1,yz=totb; while(zz<=tota&&yz>=1) { while(a[zz]+b[yz]>t)yz--; if(yz<1)break; if(a[zz]+b[yz]>mx)mx=a[zz]+b[yz]; zz++; } printf("%lld\n",max(mx,max(a[tota],b[totb]))); return 0; }
写在最后
求审核放过孩子的第一篇正经题解
欢迎各位大佬评论区指点一二,三克油