P3067 [USACO12OPEN] Balanced Cow Subsets G

原题链接

题解

设前半部分对两个集合贡献的差为a,后半部分贡献为b

a==b
差为a的组合数(被选上,和在哪个集合无关)sa 与b的组合数的sb
此时对答案的贡献为 sa·sb

所以穷举所有差的组合,然后累加

设差为集合A-集合B
每个元素对差的贡献有三种可能,要么加要么减要么不加也不减
由于只要用过就算进组合里(无论在哪个集合),所以差的正负值不重要(这是代码特性决定的)
而且同一组合可以诞生不同的差

code1

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

// Custom input and output functions
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, mid;
ll a[28] = {0};
map<int,int> id;
ll judge[(1<<22)+5] = {0};
ll len = 0;
vector<ll> use[(1<<22)+5];

void ss1(ll x, ll sum, ll now)
{
    if(x > mid)
    {
        if(!id[sum]) id[sum] = ++len;
        use[id[sum]].push_back(now);
        return;
    }

    ss1(x + 1, sum + a[x], now | (1LL << (x - 1)));
    ss1(x + 1, sum - a[x], now | (1LL << (x - 1)));
    ss1(x + 1, sum, now);
}

void ss2(ll x, ll sum, ll now)
{
    if(x > n)
    {
        ll who = id[sum];
        if(who)
            for(ll i = 0; i < use[who].size(); i++)
                judge[now | use[who][i]] = 1;
        return;
    }

    ss2(x + 1, sum + a[x], now | (1LL << (x - 1)));
    ss2(x + 1, sum - a[x], now | (1LL << (x - 1)));
    ss2(x + 1, sum, now);
}

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

    mid = n >> 1; // Optimized division by 2
    ss1(1, 0, 0);
    ss2(mid + 1, 0, 0);

    ll ans = 0;
    for(ll i = 1; i <= (1LL << n)  ; i++) ans += judge[i];

    write(ans);
    putchar('\n');
    return 0;
}

code2

#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, mid,ans=0;
ll a[13] = {0} ,b[13]={0};
unordered_map<ll, bitset<1024> >haxi;
bitset<1024> use1[1024];
ll len = 0;

void ss1(ll x, ll sum, ll now)
{
    if(x > mid)
    {
        haxi[sum].set(now);//把sum下的这种可能点亮
        return;
    }

    ss1(x + 1, sum + a[x], now | (1LL << (x - 1)));
    ss1(x + 1, sum - a[x], now | (1LL << (x - 1)));
    ss1(x + 1, sum, now);
}

void ss2(ll x, ll sum, ll now)
{
    if(x > n-mid)
    {
        bitset<1024> use (haxi[sum]);//代表前半部分达到sum的有哪些可能的组合
        use&=~use1[now];//去重,use1代表当后半部分的组合为now时,它(指代后半部分组合)在此之前已经和哪些前半部分组合过了
        ans+=use.count();
        use1[now]|=use;
        return;
    }

    ss2(x + 1, sum + b[x], now | (1LL << (x - 1)));
    ss2(x + 1, sum - b[x], now | (1LL << (x - 1)));
    ss2(x + 1, sum, now);
}

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

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

    ss1(1, 0, 0);
    ss2(1, 0, 0);

    write(ans-1);
    putchar('\n');
    return 0;
}

posted @   纯粹的  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示