题意

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

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. vue如何给它的data值赋值

    activeDisplay的值如何改变 用$set();方法 vm.$set('b', 2) 或者 Vue.set(data, 'c', 3) this.someObject = Object.ass ...

  2. 路飞学城Python-Day10

    [37.函数-命名空间]命名空间又称为name space,顾名思义就是存放名字的地方,存什么名字呢?举例说明,若变量 x = 1,存放于内存中,那名字x存放在哪里呢?名称空间正式存放名字x和1绑定关 ...

  3. PHP XML操作类DOMDocument

    不得不自已写一个.XML 的操作一直没有用过.下面是自己搜集的XML操作类 DOMDocument相关的内容. 属性: Attributes 存储节点的属性列表(只读) childNodes 存储节点 ...

  4. [洛谷P1750]KC喝咖啡

    题目大意:给你n个物品,每个物品有一个价值$v_i$和一个时间$t_i$,要你取m个物品,使得他们的美味度($\frac{\sum v_i}{\sum t_i}$)最大,求这个美味度. 解题思路:由于 ...

  5. qume-kvm 命令管理

    sudo /etc/init.d/acpid start 安装管理包工具 sudo apt install libguestfs-tools [ qemu-kvm qemu-kvm-tools vir ...

  6. 【Henu ACM Round#24 D】Iterated Linear Function

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 把B提取出来就是一个等比数列了. 求和一下会发现是这种形式. \(B*\frac{(A^n-1)}{A-1}+A^n*x\) 则求一 ...

  7. 【codeforces 67A】Partial Teacher

    [题目链接]:http://codeforces.com/problemset/problem/67/A [题意] 给一个长度为n-1的字符串; 每个字符串是'L','R','='这3种字符中的一个; ...

  8. Mysql学习总结(26)——MySQL子查询

    mysql中虽然有连接查询实现多表连接查询,但是连接查询的性能很差,因此便出现了子查询. 1.理论上,子查询可以出现在查询语句的任何位置,但实际应用中多出现在from后和where后.出现在from后 ...

  9. 传纸条 NOIP2008 洛谷1006 二维dp

    二维dp 扯淡 一道比较基本的入门难度的二维dp,类似于那道方格取数,不过走过一次的点下次不能再走(看提交记录里面好像走过一次的加一次a[i][j]的也AC了,,),我记得当年那道方格取数死活听不懂, ...

  10. Codeforces 558E 线段树处理字符串内排序

    给出长度为n的字符串,m个操作. 每一个操作有三个值 l,r,op. op==1,表示将字符串中[ l ,r ]的部分依照升序排列. op==0,表示将字符串中[ l ,r ]的部分依照降序排列. 输 ...