列表

详情


NC204267. 牛牛染颜色

描述

牛牛最近得到了一颗树,根是 1 号节点,他想要把这颗树染色。
每个节点可以染成白色和黑色,牛牛认为一种染色方案是好的当且仅当任意两个黑点的 lca(最近公共祖先)的颜色也是黑色的。
求一共有多少种好的染色的方案。

即:求树上有多少个点集  对于  满足:
答案可能很大,请输出答案对 取模后的结果。

输入描述

第一行一个整数 ,表示这棵树有  个节点。
接下来  行,每行两个整数  表示  之间有一条边。

输出描述

一行一个整数,表示所有合法的点的集合数量。

示例1

输入:

4
1 2
2 3
2 4

输出:

14

说明:

\varnothing ,\{1\},\{2\},\{3\},\{4\},\{1,2\},\{1,3\},\{1,4\},\{2,3\},\{2,4\},\{1,2,3\},\{1,2,4\},\{2,3,4\},\{1,2,3,4\}
共计14个集合满足题意。
注意:空集也算进答案里面!

示例2

输入:

6
1 2
1 3
1 4
2 5
5 6

输出:

42

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 612ms, 内存消耗: 118104K, 提交时间: 2020-04-28 21:47:16

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,MOD=1e9+7;
typedef long long ll;
ll dp[N];
int n,x,y,head[N],edg[N<<1],net[N<<1],tot;
void add(int x,int y)
{
	edg[++tot]=y,net[tot]=head[x],head[x]=tot;
}
void dfs(int x,int f)
{
	dp[x]=1;
	ll res=0;
	for(int i=head[x];i;i=net[i])
	{
		int y=edg[i];
		if(y==f)continue;
		dfs(y,x);
		dp[x]*=(dp[y]+1);
		dp[x]%=MOD;
		res=(res+dp[y])%MOD;
	}
	dp[x]+=res;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y);add(y,x);
	}
	dfs(1,0);
	cout<<(dp[1]+1)%MOD<<endl;
	return 0;
 } 

C++11(clang++ 3.9) 解法, 执行用时: 919ms, 内存消耗: 125924K, 提交时间: 2020-04-24 21:25:29

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int MAX_N=1010000;
const long long MOD=1e9+7;
long long dp[MAX_N];
vector<int>v[MAX_N];
void dfs(int x,int fa){
	int i;
	long long res=1;
	for(i=0;i<v[x].size();i++){
		int y=v[x][i];
		if(y==fa)
		continue;
		dfs(y,x);
		dp[x]=(dp[x]+dp[y]-1+MOD)%MOD;
		res=res*dp[y]%MOD;
	}
	dp[x]=(dp[x]+1+res)%MOD;
}
int main(void){
	int n,i,x,y;
	scanf("%d",&n);
	for(i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		v[x].push_back(y);
		v[y].push_back(x); 
	}
	dfs(1,0);
	printf("%lld\n",dp[1]);
	return 0;
}

上一题