[ABC184F] Programming Contest题解

前置知识

meet in middle (折半搜索)

会的大佬请跳过

不会的请自己前往oi wiki或CSDN(百度吧,少年)

解题思路

纯暴力

  看完题目考虑将每一种情况计算出来,排序后找不超过T的最大值

  因为每个数有(选/不选)两种情况

  所以总共2^n种结果

  显而易见,时间复杂度 O(2^n)

  n=40时,显然会G

正解

      引出

        暴力思路告诉我们,现在需要一种优秀的算法(奇技淫巧)来帮助我们

        从庞大的信竞知识中,我们找到了折半搜索;

        步骤

  1. 将数据分成2组,1到n/2一组,n/2+1到n为一组
  2. 每组单独算情况,存在数组中
  3. 两个结果数组单独排序(升序)
  4. a指针从第一组结果数组的第一个元素,b指针从第二组结果数组的最后一个元素(没学过指针怎么办?变量模拟即可,详见代码)
  5. 如果两个元素之和大于T,b--
  6. 否则用元素之和更新答案(正确性显然,自己思考)

    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;
    }

    写在最后

    求审核放过孩子的第一篇正经题解

             欢迎各位大佬评论区指点一二,三克油

posted @ 2023-01-13 10:24  storms11  阅读(17)  评论(0编辑  收藏  举报