Codeforces Round #332 (Div. 2) E. Sandy and Nuts

http://codeforces.com/contest/599/problem/E

题意不再多说...

我用 dp[i][type][s] 表示以i为根,包含二进制s所表示的节点(不含i)的子树的方案数,type的作用放到后面解释。

那么答案就是 dp[0][0][(1<

状态转移的时候我先分离出当前sta最低位的1(lowbit), 然后我枚举和这一位组成一颗子树的情况(这样使得枚举不会重复,队友说的。。)。

对于情况s,要判断是否有效,我枚举以i为公共祖先的点对,要求不能同时在s里,并且对于每个s中的点,与它相连的点要在s中或者等于i。

对于符合条件的s, 枚举某个点j作为子树的根, dp[i][type][sta] += dp[j][0][s] * dp[i][1][sta -s].

type == 0 表示未被分割的情况,type== 1表示另外还有子树连着根。这是为了当type==0时,我要首先判断一下以i为公共祖先的点对要都在点集里。

递归结束条件是sta == 0 时 return 1。

(感觉并没有讲清楚T^T)


#include 

using namespace std;

typedef long long ll;
#define rep(i,s,t) for(int i=int(s); i pii;

int n,m,q;
int linked[15];
ll dp[15][3][1<<13+5];
pii mlca[15][105];
int cnt_lca[15];

bool judge(int root, int s, int mods)
{
	rep(i, 0, n) if((s >> i) & 1)
	{
		if((linked[i] | mods) != mods) return false;
	}
	rep(i, 0, cnt_lca[root])
	{
		if(((s >> mlca[root][i].first) & 1) && ((s >> mlca[root][i].second) & 1)) return false;
	}
	return true;
}
ll dpit(int root, int beg, int sta) // root 0 ~ n-1
{
	if(~dp[root][beg][sta]) return dp[root][beg][sta];
	if(beg == 0)
	{
		int tmps = sta + (1 << root);
		rep(i, 0, cnt_lca[root])
		{
			if(((tmps >> mlca[root][i].first) & 1) && ((tmps >> mlca[root][i].second) & 1)) continue;
			return dp[root][beg][sta] = 0;
		}
	}
	if(sta == 0)
	{
		return 1;
	}
	ll& ret = dp[root][beg][sta];
	ret = 0;
	int has = (sta & (-sta));
	sta -= has;
	for(int s = 0; s<=sta; s++) if((s | sta) == sta)
	{
		int ss = s + has;
		if(!judge(root, ss, ss + (1 << root))) continue;
		for(int i=0; i> i) & 1)
		{
			ret += dpit(i, 0, ss - (1 << i)) * dpit(root, 1, sta - s);
		}
	}
	//cout<

你可能感兴趣的:(acm_动态规划)