zoukankan      html  css  js  c++  java
  • 第k小子集


    有n个数,共有2^n个子集,一个子集的值看做其所有数的和。
    求这2^n个子集中第K小的子集。
    n<=35。

    meet in the middle + 二分判定

    注意在双指针逼近时,相等的数带来的影响

    #include<cstdio>
    #include<algorithm>
    #define N 262500
    using namespace std;
    int n,k,a[40],half,note;
    int tmp1[N],sum1,tmp2[N],sum2;
    int l,r,mid,ans;
    void dfs(int now,int tot,int *tmp,int &sum)
    {
        if(now>note) { tmp[++sum]=tot; return; }
        dfs(now+1,tot,tmp,sum);
        dfs(now+1,tot+a[now],tmp,sum);
    } 
    bool check()
    {
        int j=sum2,cnt1,cnt2,tot=0,last=0;
        for(int i=1;i<=sum1;i++)
        {
            while(j && tmp1[i]+tmp2[j]>mid) j--;
            if(!j) break;
            cnt1=cnt2=1;
            while(i<sum1 && tmp1[i+1]==tmp1[i]) i++,cnt1++;
            while(j>1 && tmp2[j-1]==tmp2[j]) j--,cnt2++;
            tot+=last;
            if(tot>=k) return false;
            last=cnt1*cnt2;
        }
        return true;
    }
    int main()
    {
        scanf("%d%d",&n,&k); half=n>>1;
        for(int i=1;i<=n;i++) scanf("%d",&a[i]),r+=a[i];
        note=half;
        dfs(1,0,tmp1,sum1);
        note=n;
        dfs(half+1,0,tmp2,sum2);
        sort(tmp1+1,tmp1+sum1+1);
        sort(tmp2+1,tmp2+sum2+1); 
        while(l<=r)
        {
            mid=l+r>>1;
            if(check()) ans=mid,l=mid+1;
            else r=mid-1;
        }
        printf("%d",ans);
    } 
  • 相关阅读:
    Github账户注册的过程
    目前流行的源程序版本管理软件和项目管理软件都有哪些, 各有什么优缺点?
    作业二:四则运算
    学习进度
    对构建之法的一些问题
    个人介绍
    对《软件工程》课程的总结
    作业八 更新版
    作业八
    冲刺总结博客
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7270429.html
Copyright © 2011-2022 走看看