题意

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

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. shiro什么时候会进入doGetAuthorizationInfo(PrincipalCollection principals)

    shiro会进入授权方法一共有三种情况!(注解.标签.代码) 1.subject.hasRole(“admin”) 或 subject.isPermitted(“admin”):自己去调用这个是否有什 ...

  2. Storm Spout

    本文主要介绍了Storm Spout,并以KafkaSpout为例,进行了说明. 概念 数据源(Spout)是拓扑中数据流的来源.一般 Spout 会从一个外部的数据源读取元组然后将他们发送到拓扑中. ...

  3. Codeforces 845C. Two TVs 思路:简单贪心算法

    题目: 题目原文链接:http://codeforces.com/contest/845/problem/C 题意:现在我们有一个电视清单,有两个电视,电视清单上有每一个节目的开始时间和结束时间. 电 ...

  4. 在远程X server上显示图形的设置方法

    1.在服务器的/etc/ssh/sshd_config中,设置X11Forwarding yes,然后重启ssh服务,cd /etc/init.d这个目录下执行 ./ssh restart 2.在客户 ...

  5. System.getProperty可以获取的参数

    java.version Java 运行时环境版本 java.vendor Java 运行时环境供应商 java.vendor.url Java 供应商的 URL java.home Java 安装目 ...

  6. BZOJ 1050 [HAOI2006]旅行comf(最小生成树)

    题意 第一行包含两个正整数,N和M.下来的M行每行包含三个正整数:x,y和v.表示景点x到景点y之间有一条双向公路 ,车辆必须以速度v在该公路上行驶.最后一行包含两个正整数s,t,表示想知道从景点s到 ...

  7. visio使用技巧

    1.背景放大: 按住Ctrl键,滚动鼠标滚轮,即可调整背景大小,这是改变的显示比例 2.背景: 按住Ctrl+E,在背景边框处拖动图标,即可拉大或者缩小背景,这是实际更改背景大小.

  8. Python求阴影部分面积

    一.前言说明 今天看到微信群里一道六年级数学题,如下图,求阴影部分面积 看起来似乎并不是很难,可是博主添加各种辅助线,写各种方法都没出来,不得已而改用写Python代码来求面积了 二.思路介绍 1.用 ...

  9. jQuery实现点击图标div循环放大缩小功能

    很基础的一个功能,点击左下角的图标按钮,地图的整个div会变大,变大预览之后,再次点击图标按钮,地图的整个div会变小,恢复原样,两个图标在地图界面的放大和缩小时间不断的切换图标状态(箭头向里面,或者 ...

  10. Qt之QTimer

    简述 QTimer类提供了重复和单次触发信号的定时器. QTimer类为定时器提供了一个高级别的编程接口.很容易使用:首先,创建一个QTimer,连接timeout()信号到适当的槽函数,并调用sta ...