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

原题链接

题解

折半搜索
前半部分的所有组合(二进制表示)存起来,然后遍历后半部分的组合,找到第一个加起来不大于M的

= code

#define ll long long
#include<bits/stdc++.h>
using namespace std;

inline void read(ll &x) {  
	x = 0;
	ll flag = 1;
	char c = getchar();
    while(c < '0' || c > '9'){
        if(c == '-')flag = -1;
        c = getchar();
    }
	while(c >= '0' && c <= '9') {
		x = (x << 3) + (x << 1) + (c ^ 48); 
		c = getchar();
	}
	x *= flag;
}

inline void write(ll x)
{
    if(x < 0){
    	putchar('-');
		x = -x;
	}
    if(x > 9) 
		write(x / 10);
    putchar(x % 10 + '0');
}

ll n,m,mid;
ll a[23]={0},b[23]={0};
ll vala[(1<<21)+5]={0};

int main()
{
    read(n); read(m);
    mid=n>>1;
    for(ll i=1;i<=mid;i++) read(a[i]);

    for(ll i=1;i<=n-mid;i++) read(b[i]);

    ll cnt=(1<<mid);
    for(ll i=0;i<=(1<<mid)-1;i++)
        for(ll k=1;k<=mid;k++)
            if((1<<(k-1))&i) vala[i]+=a[k];

    sort(vala,vala+cnt);

    mid=n-mid;
    ll ans=0;
    for(ll i=0;i<=(1<<mid)-1;i++)
    {
        ll sum=0;
        for(ll k=1;k<=mid;k++) if((1<<(k-1))&i) sum+=b[k];
        ans+=lower_bound(vala,vala+cnt,m-sum+1)-vala;
    }
    write(ans);
    putchar('\n');
    return 0;
}
posted @ 2024-02-26 13:54  纯粹的  阅读(23)  评论(0)    收藏  举报