zoukankan      html  css  js  c++  java
  • 大奖赛 解题报告

    据说是教练从清北食堂捞的题目

    大奖赛

    题目背景

    你不努力,未来别人壁咚的墙都是你砌的!

    题目描述

    (Lancelot)市最近要举办大奖赛拉!住在市里的市民都十分兴奋,(Morgan)也不例外。他查了一下比赛的信息,发现比赛一共有(N)场,并且每一场的门票价格可能会不相等。(Morgan)留给比赛的预算是(K)元;他想知道,一共有多少种买票的方案,使得门票之和不超过(K)呢?

    输入输出格式

    输入格式:

    第一行两个整数(N)(K),代表比赛的场数和自己的预算。 第二行(N)个整数(A_i),代表每场比赛的门票价格。

    输出格式:

    一行一个整数,代表买票的总方案数。

    说明

    对于30%的数据,N<=10
    对于60%的数据,K<=10000
    对于100%的数据,1<=N<=40,0<k,Ai<=1000000000。


    30% (O(2^N)) 暴搜即可

    50% (O(NK)) 0/1背包

    100% (O(2^{N/2}log2^{N/2})) 双向搜索

    介绍一下双向搜索的方法。

    将门票价格分成平均大小的两个集合,分别对两个集合进行枚举并统计答案。

    具体实现如下,将其中一个集合所产生的状态用数组存储并排序,当枚举另一个集合得到答案(cost)时,在第一个集合产生的答案中进行二分查找(查找(k-cost)在之中的前驱位置),得到的位置即为这个(cost)产生的答案。

    这本质上其实是一种拿空间换时间的方法,把一半所产生的状态进行有序存储,在另一半产生答案时直接二分查找统计。

    可以做做这个题,差不多,送礼物

    值得一提的是,这个题我也有一点收获,是关于搜索的。

    在枚举状态时,如果我们这么枚举

    void dfs1(int now,ll cost)
    {
        if(cost>k) return;
        if(now==mid+1)
        {
            costa[++cnt]=cost;
            return;
        }
        dfs1(now+1,cost+a[i]);
        dfs2(now+1,cost);
    }
    

    那么产生的搜索树是这样的

    左右子树分别表示这个点选没选

    其中,每个粉红色的点所在的链表示一个状态,也就是说,只有叶子节点可以代表状态。这和平常的思路是比较相近的。

    但如果这样写

    void dfs1(int now,ll cost)
    {
        costa[++cnt]=cost;
        for(int i=now+1;i<=mid;i++)
            if(cost+a[i]<=k)
                dfs1(i,cost+a[i]);
    }
    

    那么产生的搜索树是这样的

    节点标号代表选中的节点在a数组的位置。

    这样,每一个节点所代表的链都是一个状态了。

    显然,第二种是比较优秀的。


    code:

    #include <cstdio>
    #include <algorithm>
    #define ll long long
    const int N=45;
    ll a[N],n,k,costa[1<<21],cnt=0,mid,ans=0;
    void dfs1(int now,ll cost)
    {
        costa[++cnt]=cost;
        for(int i=now+1;i<=mid;i++)
            if(cost+a[i]<=k)
                dfs1(i,cost+a[i]);
    }
    void find(ll x)
    {
        ll l=1,r=cnt;
        while(l<r)
        {
            ll Mid=l+r+1>>1;
            if(costa[Mid]<=x)
                l=Mid;
            else
                r=Mid-1;
        }
        ans+=l;
    }
    void dfs2(int now,ll cost)
    {
        find(k-cost);
        for(int i=now+1;i<=n;i++)
            if(cost+a[i]<=k)
                dfs2(i,cost+a[i]);
    }
    int main()
    {
        scanf("%lld%lld",&n,&k);
        for(int i=1;i<=n;i++)
            scanf("%lld",a+i);
        mid=n>>1;
        std::sort(a+1,a+1+n);
        dfs1(0,0);
        std::sort(costa+1,costa+1+cnt);
        costa[0]=-1;
        dfs2(mid,0);
        printf("%lld
    ",ans);
        return 0;
    }
    
    

    2018.6.21

  • 相关阅读:
    hugo博客使用 utterances 作为评论系统
    使用DEM生成彩色的立体图像
    hibernate Annotation 注解形式 实例 事务 hibernate.cfg.xml
    web.xml配置webAppRootKey 的问题
    JAVA 生成二维码 代码
    关于Boost库的split函数在不同的编译器下的使用
    纯 hibernate hibernate.cfg.xml 事务 数据库操作 CRUD
    Android 百度地图API 定位 导航 代码
    Android GPS
    使用GDAL对DEM进行彩色渲染
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9209818.html
Copyright © 2011-2022 走看看