zoukankan      html  css  js  c++  java
  • HZOJ 毛一琛

    直接暴搜是$3^n$的,无法接受。

    正解是$meet in the middle$,暴搜前n/2个数,每个数的状态有三种:都不选,选为A集合,选为B集合。那么我们可以维护两个集合的差。

    设状态为sta,每个数选中为1(无论是A还是B集合都为1),否则为0。差为v。

    将二元组(sta,v)插入Hash_map。

    之后暴搜后n/2个数。同样统计出状态sta和差v。在Hash_map中查询差为v的二元组个数。同时用数组v[1<<11][1<<11]记录两个状态是否选择过去重。

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    bool v[1<<11][1<<11];
    struct Hash_map
    {
    	int fi[2333333],ni[2333333],siz;
    	LL key[2333333],val[2333333];
    	inline void insert(int x,int y)
    	{
    		int k=(x%2333333+2333333)%2333333,i=fi[k];
    		for(;i;i=ni[i])if(key[i]==x&&val[i]==y)return;
    		i=++siz,key[i]=x,val[i]=y,ni[i]=fi[k],fi[k]=i;
    	}
    	inline int find(int x,int y)
    	{
    		int k=(x%2333333+2333333)%2333333,res=0;
    		for(int i=fi[k];i;i=ni[i])
    		if(key[i]==x&&!v[y][val[i]])v[y][val[i]]=1,res++;
    		return res;
    	}
    }f;
    int n,m[21];
    LL ans=0;
    void dfs(int now,int en,int sta,int vv)
    {
    	if(now==en+1)
    	{
    		if(en!=n)f.insert(vv,sta);
    		else ans+=f.find(vv,sta);
    		return;
    	}
    	dfs(now+1,en,sta<<1,vv);
    	dfs(now+1,en,sta<<1|1,vv+m[now]);
    	dfs(now+1,en,sta<<1|1,vv-m[now]);
    }
    signed main()
    {	
    //	freopen("in.txt","r",stdin);
    //	freopen("1.out","w",stdout);
    	
    	cin>>n;for(int i=1;i<=n;i++)cin>>m[i];
    	dfs(1,n/2,0,0);dfs(n/2+1,n,0,0);
    	printf("%lld
    ",ans-1);
    }
    
  • 相关阅读:
    建设是为“有” 共享是为“无”
    设计模式-命令模式
    设计模式-建造者模式
    设计模式-抽象工厂模式(升级版工厂方法模式)
    设计模式-原型模式
    设计模式-单例模式
    Java中的多维数组
    设计模式-装饰者
    设计模式-模板方法
    乐观锁与悲观锁
  • 原文地址:https://www.cnblogs.com/Al-Ca/p/11678650.html
Copyright © 2011-2022 走看看