洛谷P4799 世界冰球锦标赛 CEOI2015 Day2 meet-in-the-middle

正解:折半搜索

解题报告:

先放个传送门QAQ

想先说下部分分?因为包含了搜索背包两个方面就觉得顺便复习下?QwQ

第一档部分分 爆搜

就最最普通的爆搜鸭,dfs(第几场,钱),然后每次可以看可以不看于是dfs(+1,+钱)和dfs(+1,不变)地转移就好辣!

第二档部分分 背包

f[第几场][钱]地转移就好辣,不想多说了QwQ

然后你就能拿到70pts辣!

然后就说下,正解

正解就是,折半搜索鸭,就先处理出来前n/2场的所有花钱的方案,再处理出后n/2场的方案(就用第一档分的爆搜处理

然后upper_band每次找后面场能对应的看的场数,加起来,就好辣!

over

发现折半搜索其实做得挺susi的,代码量不大,,,我很久没有体验40minA一道题的美好感受了QAQ

 

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rp(i,x,y) for(register ll i=x;i<=y;++i)

const ll N=50,M=1100000;
ll n,m,cst[N],cnt1,cnt2,sum1[M],sum2[M],ans;

inline ll read()
{
    char ch=getchar();ll x=0;bool y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=getchar();
    if(ch=='-')ch=getchar(),y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar();
    return y?x:-x;
}
inline void dfs1(ll x,ll y)
{
    if(y>m)return ;if(x>(n>>1)){sum1[++cnt1]=y;return;}
    dfs1(x+1,y);dfs1(x+1,y+cst[x]);
}
inline void dfs2(ll x,ll y)
{
    if(y>m)return ;if(x>n){sum2[++cnt2]=y;return;}
    dfs2(x+1,y);dfs2(x+1,y+cst[x]);
}

int main()
{
    n=read();m=read();rp(i,1,n)cst[i]=read();
    dfs1(1,0);dfs2((n>>1)+1,0);
    sort(sum2+1,sum2+1+cnt2);sort(sum1+1,sum1+1+cnt1);
    rp(i,1,cnt1)ans+=upper_bound(sum2+1,sum2+1+cnt2,m-sum1[i])-sum2-1;
    printf("%lld\n",ans);
    return 0;
}
格式好像炸了???不清楚QAQ如果炸了麻烦在下面评论一句告诉我QAQ

 

 

猜你喜欢

转载自www.cnblogs.com/lqsukida/p/10308428.html