P4799-世界冰球锦标赛(折半枚举模板)

题目
P4799-世界冰球锦标赛(折半枚举模板)_第1张图片1<=n<=40,1<=m<=1e18;
输入样例#1:
5 1000
100 1500 500 500 1000

输出样例#1:
8

01背包,m范围小的话可以使用。这里是错误的。因为m<=1e18;

#include
using namespace std;
typedef long long ll;
const int N=1e6+5e4;
int a[N];ll dp[N];
int main()
{
    int n,m;scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    dp[0]=1;
    for(int i=1;i<=n;i++)
        for(int j=m;j>=a[i];j--)
            dp[j]+=dp[j-a[i]];
    ll ans=0;
    for(int i=0;i<=m;i++)
        ans+=dp[i];
    printf("%lld\n",ans);
}

折半枚举(meet int the middle)

#include
#include
#include
#include
#define m(a,b) memset(a,b,sizeof a)
#define en '\n'
using namespace std;
typedef long long ll;
const int N=1e6+5e4;
ll a[N],fin1[N],fin2[N],cnt1,cnt2;
int n;ll m;
void dfs1(int pos,ll sum)
{
    if(sum>m)
        return;
    if(pos==(n/2+1))
    {
        fin1[++cnt1]=sum;
        return;
    }
    dfs1(pos+1,sum+a[pos]);
    dfs1(pos+1,sum);
}
void dfs2(int pos,ll sum)
{
    if(sum>m)
        return;
    if(pos==(n+1))
    {
        fin2[++cnt2]=sum;
        return;
    }
    dfs2(pos+1,sum+a[pos]);
    dfs2(pos+1,sum);
}
int main()
{
    cnt1=0,cnt2=0;
    scanf("%d%lld",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    dfs1(1,0),dfs2(n/2+1,0);
    sort(fin1+1,fin1+cnt1+1);
    sort(fin2+1,fin2+cnt2+1);
    ll ans=0;
    for(int i=1;i<=cnt1;i++)
        ans+=upper_bound(fin2+1,fin2+cnt2+1,m-fin1[i])-fin2-1;
    printf("%lld\n",ans);
}

你可能感兴趣的:(基本算法==折半枚举)