洛谷P3067 平衡的奶牛群 [USACO12OPEN] meet-in-the-middle

正解:搜索

解题报告:

先放下传送门QwQ

这题就,双向搜索经典题鸭

首先dfs应该挺好想到的我jio得?就是我们不用记录左右分别得分多少只要记下差值就好了嘛能get?

然后就先搜左边,记录下每个得分的数量

然后再搜右边,每搜出一个ans+=之前左边的可能得分数量

然后就欧克克了!

啊对了,,,还有一个细节卡了我好久QAQ

就是,要判重

因为注意题意它只是问选数的方案

所以我举个eg哦,假如选出了3 3 3 3,那它就会被枚举24=16次

所以为了避免这种情况

就用个状压

就over了!

具体一点细节晚上写趴,,,QAQ

(还有就是,这题有个双倍经验,,,只是好像要加一点儿细节什么的QwQ我有时间把细节什么的补上来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=22;
ll n,m,as,gg[N],cnta,cntb,l=1,r=1;
struct node{ll sm,zt;}a[1<<N],b[1<<N];
bool vis[1<<N];

inline ll read()
{
    register char ch=getchar();register ll x=0;register 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;
}
void dfs1(ll x,ll y,ll zt)
{
    if(x>(n>>1)){a[++cnta].sm=y;a[cnta].zt=zt;return;}
    dfs1(x+1,y,zt);dfs1(x+1,y+gg[x],zt|(1<<x));dfs1(x+1,y-gg[x],zt|(1<<x));
    return;
}
void dfs2(ll x,ll y,ll zt)
{
    if(x>n){b[++cntb].sm=y;b[cntb].zt=zt;return;}
    dfs2(x+1,y,zt);dfs2(x+1,y+gg[x],zt|(1<<x));dfs2(x+1,y-gg[x],zt|(1<<x));
    return;
}
inline bool cmp1(node gd,node gs){return gd.sm<gs.sm;}
inline bool cmp2(node gd,node gs){return gd.sm>gs.sm;}

int main()
{
    n=read();rp(i,1,n)gg[i]=read();
    dfs1(1,0,0);dfs2((n>>1)+1,0,0);
    sort(a+1,a+1+cnta,cmp1);sort(b+1,b+1+cntb,cmp2);
    while(l<=cnta && r<=cntb)
    {
        while(a[l].sm+b[r].sm>0 && r<=cntb)++r;
        ll wz=r;
        while(r<=cntb && b[r].sm+a[l].sm==0){if(!vis[a[l].zt|b[r].zt])vis[a[l].zt|b[r].zt]=1,++as;++r;}
        if(l<cnta && a[l].sm==a[l+1].sm)r=wz;
        ++l;
    }
    printf("%lld\n",as-1);
    return 0;
}
这是写了好久还有一个点T了最后吸氧苟过去的代码!

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值