题意

给一棵树,你可以匹配有边相连的两个点,问你这棵树的最大匹配时多少,并且计算出有多少种最大匹配。

N≤1000,其中40%的数据答案不超过 108

题解

显然的树形DP+高精。

这题是作为考试题考的,因为记得有一次考试,状态用两个数组存。

所以看到这题瞬间想到状态dp[i][0/1]代表以i为根的子树不选/选i点的最大匹配数。

f[i][0/1]代表以i为根的子树中不选/选i形成最大匹配的方案数。

然后方程改了半天:而且极长所以看代码吧。

TM还要加高精。。。

(第一个点挂了,特判过的)

 #include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const long long N=;
long long dp[N][],cnt,head[N],sum1[N],sum[N],n;
struct num{
long long a[],l;
}z,f[N][];
num add(num a,num b){
if(a.l<b.l)swap(a,b);
for(long long i=;i<=b.l;i++){
a.a[i]+=b.a[i];
}
for(long long i=;i<=a.l;i++)
if(a.a[i]>=){
a.a[i+]+=;
a.a[i]-=;
if(i==a.l)a.l++;
}
return a;
}
num mul(num a,num b,num c){
for(long long i=;i<=a.l;i++)
for(long long j=;j<=b.l;j++){
c.a[i+j-]+=a.a[i]*b.a[j];
}
long long top=;
for(long long i=;i<=a.l+b.l;i++){
if(c.a[i])top=i;
c.a[top+]+=c.a[top]/;
c.a[top]%=;
}
c.l=top;
return c;
}
struct edge{
long long to,nxt;
}e[N*];
void add(long long u,long long v){
cnt++;
e[cnt].nxt=head[u];
e[cnt].to=v;
head[u]=cnt;
}
void getdp(long long u,long long fa){
long long sum=;
long long tmp=;
num tmpp;
tmpp.a[]=;
tmpp.l=;
for(long long i=head[u];i;i=e[i].nxt){
long long v=e[i].to;
if(v==fa)continue;
getdp(v,u);
sum+=dp[v][];
if(dp[v][]==dp[v][]&&dp[v][])tmpp=mul(tmpp,add(f[v][],f[v][]),z);
else tmpp=mul(tmpp,f[v][],z);
}
dp[u][]=sum;
f[u][]=tmpp;
tmp=;
tmpp.a[]=;
tmpp.l=;
for(long long i=head[u];i;i=e[i].nxt){
long long v=e[i].to;
if(v==fa)continue;
if(sum-dp[v][]+dp[v][]+==tmp){
num tmppp=f[v][];
for(long long j=head[u];j;j=e[j].nxt){
long long vv=e[j].to;
if(vv==fa||v==vv)continue;
if(dp[vv][]==dp[vv][]&&dp[vv][])tmppp=mul(tmppp,add(f[vv][],f[vv][]),z);
else tmppp=mul(tmppp,f[vv][],z);
}
tmpp=add(tmpp,tmppp);
}
if(sum-dp[v][]+dp[v][]+>tmp){
tmp=sum-dp[v][]+dp[v][]+;
tmpp=f[v][];
for(long long j=head[u];j;j=e[j].nxt){
long long vv=e[j].to;
if(vv==fa||v==vv)continue;
if(dp[vv][]==dp[vv][]&&dp[vv][])tmpp=mul(tmpp,add(f[vv][],f[vv][]),z);
else tmpp=mul(tmpp,f[vv][],z);
}
}
}
dp[u][]=tmp;
f[u][]=tmpp;
}
void write(num x){
if(x.l==&&x.a[]==){
cout<<;
return;
}
for(long long i=x.l;i>=;i--){
printf("%lld",x.a[i]);
}
}
int main(){
scanf("%lld",&n);
for(long long i=;i<=n;i++){
long long m,u;
scanf("%lld%lld",&u,&m);
for(long long j=;j<=m;j++){
long long a;
scanf("%lld",&a);
add(u,a);add(a,u);
}
}
getdp(,);
if(dp[][]>dp[][]){
printf("%lld\n",dp[][]);
write(f[][]);
}
else if(dp[][]<dp[][]){
printf("%lld\n",dp[][]);
write(f[][]);
}
else {
printf("%lld\n",dp[][]);
write(add(f[][],f[][]));
}
return ;
}

[CEOI2007]树的匹配Treasury(树形DP+高精)的更多相关文章

  1. luogu P1623 [CEOI2007]树的匹配Treasury

    题目链接 luogu P1623 [CEOI2007]树的匹配Treasury 题解 f[i][0/1]表示当前位置没用/用了 转移暴力就可以了 code // luogu-judger-enable ...

  2. [CEOI2007] 树的匹配Treasury

    类型:树形 DP 传送门:>Here< 题意:给一棵树,你可以匹配有边相连的两个点,问你这棵树的最大匹配是多少,并且计算出有多少种最大匹配. 解题思路 首先树形Dp是很明显的,$f[i][ ...

  3. BZOJ5123 线段树的匹配(树形dp)

    线段树的任意一棵子树都相当于节点数与该子树相同的线段树.于是假装在树形dp即可,记忆化搜索实现,有效状态数是logn级别的. #include<iostream> #include< ...

  4. 洛谷P4608 [FJOI2016]所有公共子序列问题 【序列自动机 + dp + 高精】

    题目链接 洛谷P4608 题解 建个序列自动机后 第一问暴搜 第二问dp + 高精 设\(f[i][j]\)为两个序列自动机分别走到\(i\)和\(j\)节点的方案数,答案就是\(f[0][0]\) ...

  5. 1113: [视频]树形动态规划(TreeDP)8:树(tree)(树形dp状态设计总结)

    根据最近做的几道树形dp题总结一下规律.(从这篇往前到洛谷 P1352 ) 这几道题都是在一颗树上,然后要让整棵树的节点或边 满足一种状态.然后点可以影响到相邻点的这种状态 然后求最小次数 那么要从两 ...

  6. poj3107(树的重心,树形dp)

    题目链接:https://vjudge.net/problem/POJ-3107 题意:求树的可能的重心,升序输出. 思路:因为学树形dp之前学过点分治了,而点分治的前提是求树的重心,所以这题就简单水 ...

  7. BZOJ1089 [SCOI2003]严格n元树 【dp + 高精】

    Description 如果一棵树的所有非叶节点都恰好有n个儿子,那么我们称它为严格n元树.如果该树中最底层的节点深度为d (根的深度为0),那么我们称它为一棵深度为d的严格n元树.例如,深度为2的严 ...

  8. 【bzoj1907】树的路径覆盖 树形dp

    题目描述 输入 输出 样例输入 1 7 1 2 2 3 2 4 4 6 5 6 6 7 样例输出 3 题解 树形dp 设f[x]表示以x为根的子树完成路径覆盖,且x为某条路径的一端(可以向上延伸)的最 ...

  9. bzoj 1089: [SCOI2003]严格n元树【dp+高精】

    设f[i]为深度为i的n元树数目,s为f的前缀和 s[i]=s[i-1]^n+1,就是增加一个根,然后在下面挂n个子树,每个子树都有s[i-1]种 写个高精就行了,好久没写WA了好几次-- #incl ...

随机推荐

  1. xBIM 基础09 WeXplorer 基本应用

    系列目录    [已更新最新开发文章,点击查看详细]  在本教程中,将学习如何创建最基本和最直接的查看器. 除了展示建筑模型外,不做其他任何操作.它将只使用内置导航,但是不会对按钮做出事件响应. &l ...

  2. Net Core链接数据库

    原文 在Windows下,相信大家分分钟都可以搞定.而初次接触.net core + mysql可能需要注意些细节.首先打开vs2017新建一个asp.net core项目(选Web应用程序), 然后 ...

  3. java中三个类别加载器的关系以及各自加载的类的范围

    Java在需要使用类别的时候,才会将类别加载,Java的类别载入是由类别载入器(Class loader)来达到的,预设上,在程序启动之后,主要会有三个类别加载器:Bootstrap Loader.E ...

  4. 记我安装Caffe的血泪史(2)

    不知不觉居然花了一个星期来安装Caffe...真是醉了. 接上一篇blog,本以为编译完cuda,opencv之后问题就差不多了(其实本来是没有什么问题的,但硬是被我搞了一堆事情出来....) 出于对 ...

  5. stm8s103 EEPROM烧程序时能否保留

    EEPROM的参数需要再烧录程序时保留,做试验测试是否能够保留 1.在ST Visual Develop中硬件仿真手动修改EEPROM的值. 2.在ST Visual Programmer中读取EEP ...

  6. 注解形式读取properties文件中的属性

    1.spring.xml中加入(多个properties 用逗号隔开)  <context:property-placeholder location="classpath:jdbc. ...

  7. hihocoder 1124 : 好矩阵 dp

    好矩阵 时间限制:3000ms 单点时限:1000ms 内存限制:256MB 描写叙述 给定n, m.一个n × m矩阵是好矩阵当且仅当它的每一个位置都是非负整数,且每行每列的和 ≤ 2.求好矩阵的个 ...

  8. XUtils3框架的基本用法(一)

    本文为作者原创,转载请指明出处: http://blog.csdn.net/a1002450926/article/details/50341173 今天给大家带来XUtils3的基本介绍.本文章的案 ...

  9. MapReduce 的类型与格式【编写最简单的mapreduce】(1)

    hadoop mapreduce 中的map 和reduce 函数遵循下面的形式 map: (K1, V1) → list(K2, V2) reduce: (K2, list(V2)) → list( ...

  10. Block的使用--初探Block

    看了两天的Block. 网上是有非常多解说与教程,也有讲得非常好的.这里就主要解说下我的理解与收获.欢迎拍砖. 所谓block.我觉得应该是一个闭包函数.而闭包,就是说block以及内部全部的变量生命 ...