hdu5977 Garden of Eden 2016大连区域赛G题

安稳与你 提交于 2020-01-12 21:22:58

http://acm.hdu.edu.cn/showproblem.php?pid=5977

点分治,对于每个重心u计算出经过u且能构成当前需要的满状态ss的方案数。

对于每条到u的路径,我们得到这条路径上有的种类的状态压缩的数字a[i]

然后枚举a[i]的每个子集(可以在calc中枚举,也可以在外面枚举存在vector))  s0,sum[s0]++,说明a[i]是包含s0的,s0是a[i]的子集,sum[s0]就是包含s0的路径有多少条,这样就可以计算出所需方案数了。

注意我们要减去同一棵子树中的非法组合,而对于u的所有子节点v来说,v的路径能组成(mi[k+1]-1)^(mi[mp[u]])也就是默认带上u节点上的苹果,所能凑出所有苹果的路径组合的方案数,就是子树v对于u来说的非法组合数。

O(nlogn*2^k)的复杂度,虽然很大,不过其实子集数量其实是比较少的,且递归越深子集数量越少,基本卡不掉。

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

const int maxl=5e4+10;

int n,k,m,cnt,len;
long long ans;
int a[maxl],ehead[maxl],typ[maxl],mi[12],dy[1024];
int st[maxl],sum[maxl];
struct ed
{
	int to,nxt;
}e[maxl<<1];
vector <int> ziji[1024];
bool vis[maxl];
struct centertree
{
	int n,ans,mini;
	int son[maxl];
	inline void dfs(int u,int fa)
	{
		son[u]=1;int mx=0,v;
		for(int i=ehead[u];i;i=e[i].nxt)
		{
			v=e[i].to;
			if(v==fa || vis[v]) continue;
			dfs(v,u);
			son[u]+=son[v];
			mx=max(son[v],mx);
		}
		mx=max(mx,n-son[u]);
		if(mx<mini)
		{
			mini=mx;
			ans=u;
		}
	}
	inline int getcenter(int u)
	{
		ans=0;mini=2e9;
		dfs(u,0);
		return ans;
	}
}tree;

inline void add(int u,int v)
{
	e[++cnt].to=v;e[cnt].nxt=ehead[u];ehead[u]=cnt;
}

inline void prework()
{
	for(int i=1;i<=n;i++)
		ehead[i]=0,vis[i]=false;
	for(int i=1;i<=n;i++)
		scanf("%d",&typ[i]);
	int u,v;cnt=0;
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		add(u,v);add(v,u);
	}
}

inline void getst(int u,int fa)
{
	a[++len]=st[u];
	int v;
	for(int i=ehead[u];i;i=e[i].nxt)
	{
		v=e[i].to;
		if(v==fa || vis[v]) continue;
		st[v]=st[u] | mi[typ[v]];
		getst(v,u);
	}
}

inline long long calc(int u,int ss)
{
	len=0;
	st[u]=mi[typ[u]];
	getst(u,0); 
	for(int i=0;i<mi[k+1];i++)
		sum[i]=0;
	long long ret=0;
	for(int i=1;i<=len;i++)
		for(auto s0 : ziji[a[i]])
			sum[s0]++;
	sum[0]=len;
	int s;
	for(int i=1;i<=len;i++)
	{
		s=ss&a[i];
		ret+=sum[ss^s];	
	}
	return ret;
	
} 

inline void solv(int u)
{
	vis[u]=true;
	ans+=calc(u,mi[k+1]-1);
	int v,rt;
	for(int i=ehead[u];i;i=e[i].nxt)
	{
		v=e[i].to;
		if(vis[v]) continue;
		ans-=calc(v,(mi[k+1]-1)^mi[typ[u]]);
		tree.n=tree.son[v];
		rt=tree.getcenter(v);
		solv(rt);
	}
}

inline void mainwork()
{
	ans=0;tree.n=n;
	int rt=tree.getcenter(1);
	solv(rt);
}

inline void print()
{
	printf("%lld\n",ans);
}

int main()
{
	for(int i=1;i<=11;i++)
		mi[i]=1<<(i-1),dy[mi[i]]=i;
	for(int i=1;i<1024;i++)
		for(int s0=i;s0;s0=(s0-1)&i)
			ziji[i].push_back(s0); 
	while(~scanf("%d%d",&n,&k))
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!