[CEOI2007]树的匹配Treasury(树形DP+高精)
题意
给一棵树,你可以匹配有边相连的两个点,问你这棵树的最大匹配时多少,并且计算出有多少种最大匹配。
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+高精)的更多相关文章
- luogu P1623 [CEOI2007]树的匹配Treasury
题目链接 luogu P1623 [CEOI2007]树的匹配Treasury 题解 f[i][0/1]表示当前位置没用/用了 转移暴力就可以了 code // luogu-judger-enable ...
- [CEOI2007] 树的匹配Treasury
类型:树形 DP 传送门:>Here< 题意:给一棵树,你可以匹配有边相连的两个点,问你这棵树的最大匹配是多少,并且计算出有多少种最大匹配. 解题思路 首先树形Dp是很明显的,$f[i][ ...
- BZOJ5123 线段树的匹配(树形dp)
线段树的任意一棵子树都相当于节点数与该子树相同的线段树.于是假装在树形dp即可,记忆化搜索实现,有效状态数是logn级别的. #include<iostream> #include< ...
- 洛谷P4608 [FJOI2016]所有公共子序列问题 【序列自动机 + dp + 高精】
题目链接 洛谷P4608 题解 建个序列自动机后 第一问暴搜 第二问dp + 高精 设\(f[i][j]\)为两个序列自动机分别走到\(i\)和\(j\)节点的方案数,答案就是\(f[0][0]\) ...
- 1113: [视频]树形动态规划(TreeDP)8:树(tree)(树形dp状态设计总结)
根据最近做的几道树形dp题总结一下规律.(从这篇往前到洛谷 P1352 ) 这几道题都是在一颗树上,然后要让整棵树的节点或边 满足一种状态.然后点可以影响到相邻点的这种状态 然后求最小次数 那么要从两 ...
- poj3107(树的重心,树形dp)
题目链接:https://vjudge.net/problem/POJ-3107 题意:求树的可能的重心,升序输出. 思路:因为学树形dp之前学过点分治了,而点分治的前提是求树的重心,所以这题就简单水 ...
- BZOJ1089 [SCOI2003]严格n元树 【dp + 高精】
Description 如果一棵树的所有非叶节点都恰好有n个儿子,那么我们称它为严格n元树.如果该树中最底层的节点深度为d (根的深度为0),那么我们称它为一棵深度为d的严格n元树.例如,深度为2的严 ...
- 【bzoj1907】树的路径覆盖 树形dp
题目描述 输入 输出 样例输入 1 7 1 2 2 3 2 4 4 6 5 6 6 7 样例输出 3 题解 树形dp 设f[x]表示以x为根的子树完成路径覆盖,且x为某条路径的一端(可以向上延伸)的最 ...
- bzoj 1089: [SCOI2003]严格n元树【dp+高精】
设f[i]为深度为i的n元树数目,s为f的前缀和 s[i]=s[i-1]^n+1,就是增加一个根,然后在下面挂n个子树,每个子树都有s[i-1]种 写个高精就行了,好久没写WA了好几次-- #incl ...
随机推荐
- java日期类型与字符串类型的相互转换
package cn.zwq.convert; import java.text.ParseException; import java.text.SimpleDateFormat; import j ...
- 51nod 1632 B君的连通
题目: 这题看起来难,其实这么多概率啥的都是唬人的.甚至连快速幂都不用就可以解. 解法: n个节点,n-1条边,期望会有一半的边被炸毁(因为总体概率就是50%). 即(n-1)/2条边被炸毁,这 ...
- split(":")[0].substring(1)
java中拆分字符中的split(":")[0].substring(1)是什么意思啊,尤其[0] 可以解释一下吗?:比如你有一个字符串 "111:222:333&quo ...
- 《鸟哥的Linux私房菜》笔记——01. 计算机概论
计算机的五大部分:输入单元.输出单元.CPU(控制单元(Control Unit).算数逻辑单元(ALU)).内存. CPU 的架构 精简指令集(Reduced Instruction Set Com ...
- SpringBoot学习笔记(9)----SpringBoot中使用关系型数据库以及事务处理
在实际的运用开发中,跟数据库之间的交互是必不可少的,SpringBoot也提供了两种跟数据库交互的方式. 1. 使用JdbcTemplate 在SpringBoot中提供了JdbcTemplate模板 ...
- 在学校机房联想硬盘保护下安装Linux,并配置锐捷客户端
最近几天一直在机房里刷题,空调开着非常舒服.但是机房电脑里全是windows系统,不太好用,挺膈应人的. 一直打算换个系统,刚才终于搞定网络问题了,以后用电脑就可以爽到了. 联想硬盘保护系统下u盘安装 ...
- HDU-5685 Problem A 求乘法逆元
题目链接:https://cn.vjudge.net/problem/HDU-5685 题意 给一个字符串S和一个哈希算法 $ H(s)=\prod_{i=1}^{i\leq len(s)}(S_{i ...
- 获取mapper
static UpdateLogMapper updateLogMapper = (UpdateLogMapper)SpringContextUtil.getBean(UpdateLogMapper. ...
- nginx 多级7层代理安装配置
编译安装 yum install zlib-devel -y wget https://nginx.org/download/nginx-1.15.12.tar.gz tar -zxf nginx-1 ...
- Linux 添加挂载硬盘(包含挂载大于2T以上硬盘)
转自:http://blog.csdn.net/season_hangzhou/article/details/36423223 由于事先规划问题或者业务需求量激增,总会出现机器硬盘空间不够用的情况 ...