P4799 [CEOI2015 Day2]世界冰球锦标赛

\(0-1\)背包解法

适用数据范围:\(N≤40,M≤10^6\)
状态表示:\(f(i,j)\):从前\(i\)个物品中选,花费不超过(小于等于)\(j\)的方案数。
最后累加\(f(n,0~m)\)即可。

const int N=45,M=1e6+10;
LL price[N];
LL f[M];
LL n,m;
LL ans;

int main()
{
    cin>>n>>m;

    for(int i=1;i<=n;i++) cin>>price[i];

    f[0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=m;j>=price[i];j--)
        {
            f[j]+=f[j-price[i]];
        }
    }

    for(int i=0;i<=m;i++) ans+=f[i];
    cout<<ans<<endl;

    //system("pause");
}

折半搜索——正解

我们可以将所有比赛分成两部分,对这两部分分别进行指数型枚举,然后使用vector来储存搜索过程中产生的可能的花费。

最后再将两部分进行合并,得出最终的答案。

时间复杂度:\(O(2^{\frac{n}{2}}log2^{\frac{n}{2}})\)

const int N=45;
LL price[N];
vector<LL> suml;
vector<LL> sumr;
LL n,m;
LL ans;

void dfs(int l,int r,LL sum,vector<LL> &v)
{
    if(l>r)
    {
        v.pb(sum);
        return;
    }
    if(sum + price[l] <= m) dfs(l+1,r,sum+price[l],v);
    dfs(l+1,r,sum,v);
}

int main()
{
    cin>>n>>m;

    for(int i=0;i<n;i++) cin>>price[i];

    dfs(0,n/2-1,0,suml);
    dfs(n/2,n-1,0,sumr);

    sort(suml.begin(),suml.end());

    for(int i=0;i<sumr.size();i++)
    {
        ans+=upper_bound(suml.begin(),suml.end(),m-sumr[i])-suml.begin();
    }

    cout<<ans<<endl;
    //system("pause");
}
posted @ 2020-12-13 15:18  Dazzling!  阅读(90)  评论(0编辑  收藏  举报