[Ceoi2007]Royaltreasury
#1945. [Ceoi2007]Royaltreasury
Online Judge:Bzoj-1945
Label:树形Dp,高精度
题目描述
在很久很久以前的一个王国里,王国的财产开始变得越来越少。国王决定改变这种情况,然后他发明了一种新的系统。系统职员要求两两成对(为了避免行贿),每一对由一个职员及他的下属组成。你的任务就是在满足这种组成方式结构的前提下,计算出能够按照这种方式组成的最大的对数,和可能的方法数。
这项任务是由George Skinflint领导的。每个职员都有0个,1个或者更多的下属,并且每个职员都只有一个单独的上司(除了George Skinglint)。职员的人数不会超过1 000。你的任务就是,按照由职员及他的下属组成的方法,计算出能够组成的对数的最大值。另外,你也要计算最大值可能的组成的方式有多少种。注意一些职员不需要成对。
输入
第一行包含一个数字N,表示职员的数目,1≤N≤1000。职员按照特殊的ID号码进行标号,号码为1~N。Skinflint的号码为1。接下来N行对应相应的职员:包含其ID号和一个数字K表示他的下属的数目,0≤K≤999,接下来给出他的K个职员的ID号,中间由空格分隔。并且保证所有职员不会比他的上司先出现。
输出
输出包含两行。第一行包含一个单独的数字,代表职员能形成的最多的对数。第二行表示在多数最多的情况下,有多少种形成方式。
样例输入
7
1 3 2 4 7
2 1 3
4 1 6
3 0
7 1 5
5 0
6 0
样例输出
3
4
题解:
题目大意就是给定一棵n个节点的树,让你将父亲节点和儿子节点配对,问最多能组几对,且能达到这个最大值的配对方案有几种。
由于n<=1000,考虑树形Dp,定义状态:\(dp[x][0]\)表示不选x时,x的子树(包含x)最多能组的对数,\(dp[x][1]\)表示选x时,x的子树(包含x)最多能组的对数。相应的定义数组\(cnt[x][0],cnt[x][1]\)表示不选/选x时,达到最大值的方案数。
我们知道,当解决完x的子树后,就可以得到上述四个值,由于只有最优情况会对父亲节点做出贡献,为了方便向上回溯统计,直接在得到上述四个值后选出最优答案。具体实现如下,我们把最优解存在\(dp[x][1],cnt[x][1]\)上,那么最终答案就是\(dp[1][1],cnt[1][1]\)。
也就是说,只有当处于x这一层时,\(dp[x][1],cnt[x][1]\)才表示选择x的状态。
if(dp[x][1]<dp[x][0]){
dp[x][1]=dp[x][0];
cnt[x][1]=cnt[x][0];
}
else if(dp[x][1]==dp[x][0])cnt[x][1]=cnt[x][1]+cnt[x][0];
接下来考虑如何转移。设当前层为x。
Status1:当不选x时,那么x的儿子选或不选都可以,那直接每个儿子都选最优情况,只要将\(cnt[x][0]*=cnt[son][1],dp[x][0]+=dp[son][1]\)即可,注意由于在搞x之前已经先递归子树了,这里的\(cnt[son][1],dp[son][1]\)就已经表示儿子的最优情况(联系上面对状态的定义)。
Status2:如果选择x情况就比较复杂了,必须选且仅选一个儿子与x组对,而剩下的儿子可以不选或选——选的话就是那个儿子跟他的儿子组对了,这与x无瓜。那具体怎么处理呢??我们在求Status1的时候已经得到了\(dp[x][0]\),那么只要将其中一个儿子p与x组对即可,其他儿子还是选最优情况。如何确定与x组对的儿子p呢,设p的最优解为best,当p不选时(如果p不选的话我们就可以把他和x组一对了)的最优情况为unchoose,那么只要找一个best-unchoose最小的即可——(注意可能存在多个p,此时对\(dp[x][1]\)并无影响,但对方案数\(cnt[x][1]\)会有影响,下面将会讨论到), 我们统计这个最小差值mi,则\(mi=min(dp[son][1]-dp[son][0])\),那么\(dp[x][1]=dp[x][0]-mi+1\),后面那个1是x与p新组的对数。那么如何求\(cnt[x][1]\)呢??我们根据那个mi值找到儿子p(可能会存在多个),然后根据下面的过程统计,详见注释。
for(int i=0; i<e[x].size(); i++) {
int y=e[x][i];//上文提到的儿子p
if(mi==dp[y][1]-dp[y][0]) {
BigInt s;s.init(1);
for(int j=0; j<e[x].size(); j++) {//除了p的其他儿子
int z=e[x][j];
if(z==y)s=s*cnt[z][0];
else s=s*cnt[z][1];//统计方案数
}
cnt[x][1]=cnt[x][1]+s;//由于可能存在多个儿子p,根据加法原理统计
}
}
到此此题就结束了,但是——,发现cnt方案数可能会很大,所以得用高精,而至于dp的值嘛不会超过n<=1000,所以int就够了。ps:下面的高精模板挺好用的233
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
const int P=10000;
int n,dp[N][2];
vector<int>e[N];
struct BigInt {
int len,a[100];
BigInt() {
len=0;
memset(a,0,sizeof(a));
}
void init(int x) {
memset(a,0,sizeof(a));
len=0;
do {
a[++len]=x%P;
x/=P;
} while(x);
}
void output() {
printf("%d",a[len]);
for(int i=len-1; i>=1; i--)printf("%04d",a[i]);
puts("");
}
BigInt operator *(BigInt x) {
BigInt now;
now.len=len+x.len-1;
for(int i=1; i<=len; i++)
for(int j=1; j<=x.len; j++)now.a[i+j-1]+=a[i]*x.a[j];
for(int i=1; i<=now.len; i++) {
now.a[i+1]+=now.a[i]/P;
now.a[i]%=P;
}
while(now.a[now.len+1])now.len++;
return now;
}
BigInt operator +(BigInt x) {
BigInt now;
now.len=max(len,x.len);
for(int i=1; i<=now.len; i++)now.a[i]=x.a[i]+a[i];
for(int i=1; i<=now.len; i++) {
now.a[i+1]+=now.a[i]/P;
now.a[i]%=P;
}
while(now.a[now.len+1])now.len++;
return now;
}
} cnt[N][2];
void dfs(int x) {
cnt[x][0].init(1);
int mi=1e9;
for(int i=0; i<e[x].size(); i++) {
int y=e[x][i];
dfs(y);
cnt[x][0]=cnt[x][0]*cnt[y][1];
dp[x][0]+=dp[y][1];
mi=min(dp[y][1]-dp[y][0],mi);
}
dp[x][1]=dp[x][0]-mi+1;
for(int i=0; i<e[x].size(); i++) {
int y=e[x][i];
if(mi==dp[y][1]-dp[y][0]) {
BigInt s;
s.init(1);
for(int j=0; j<e[x].size(); j++) {
int z=e[x][j];
if(z==y)s=s*cnt[z][0];
else s=s*cnt[z][1];
}
cnt[x][1]=cnt[x][1]+s;
}
}
if(dp[x][1]<dp[x][0]) {
dp[x][1]=dp[x][0];
cnt[x][1]=cnt[x][0];
} else if(dp[x][1]==dp[x][0])cnt[x][1]=cnt[x][1]+cnt[x][0];
}
int main() {
scanf("%d",&n);
for(int i=1,id,k,u; i<=n; i++) {
scanf("%d%d",&id,&k);
for(int j=1; j<=k; j++) {
scanf("%d",&u);
e[id].push_back(u);
}
}
dfs(1);
printf("%d\n",dp[1][1]);
cnt[1][1].output();
}
[Ceoi2007]Royaltreasury的更多相关文章
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- luogu P1623 [CEOI2007]树的匹配Treasury
题目链接 luogu P1623 [CEOI2007]树的匹配Treasury 题解 f[i][0/1]表示当前位置没用/用了 转移暴力就可以了 code // luogu-judger-enable ...
- [CEOI2007] 树的匹配Treasury
类型:树形 DP 传送门:>Here< 题意:给一棵树,你可以匹配有边相连的两个点,问你这棵树的最大匹配是多少,并且计算出有多少种最大匹配. 解题思路 首先树形Dp是很明显的,$f[i][ ...
- [CEOI2007]树的匹配Treasury(树形DP+高精)
题意 给一棵树,你可以匹配有边相连的两个点,问你这棵树的最大匹配时多少,并且计算出有多少种最大匹配. N≤1000,其中40%的数据答案不超过 108 题解 显然的树形DP+高精. 这题是作为考试题考 ...
随机推荐
- python的object(转)
原文章:https://www.cnblogs.com/sesshoumaru/p/6042322.html 1. object类是Python中所有类的基类,如果定义一个类时没有指定继承哪个类,则默 ...
- Fence
Fence 有一个长度为n的\([1,n]\)墙,有k位工人,第i位工人有参数\(s_i,p_i,l_i\),意思该位工人可以刷包含\(s_i\)的长度小于等于\(l_i\)的区间,报酬为区间长度乘以 ...
- [JZOJ3692] 【SRM 611】ElephantDrinking
题目 题目大意 我真的不知道怎么用简短的语言表述出来-- 直接看题目吧-- 正解 假设只有左边和上边延伸过来的,那似乎很好办:设\(f_{i,j}\)表示左上方到\((i,j)\)所形成的矩形中,如果 ...
- 【JZOJ6388】小w的作业
description analysis 二分一个角度,首先假设该弧度角\(\theta \in[{\pi \over 2},\pi]\),要找的直线斜率\(k\in(-∞,\tan\theta]\) ...
- nginx反向代理时有无”/”的辨析
nginx反向代理是日常使用nginx时最常用到的功能之一.在配置url的过程中,“/”的有无经常是影响我们配置成功的关键,也是困扰我们的问题所在.在此,结合实际例子,作简要辨析. 场景一:利用根目录 ...
- java反射快速入门
笔记记在了掘金,发现掘金的markdown编辑器比博客园样式要好看不少 https://juejin.im/post/5d4e575af265da03e4674e9f
- js日常总结
1.html如何引入css和js文件 css:<link rel="stylesheet" href="css/index1.css(这是我的文件的地址)" ...
- hdu多校第四场 1003 (hdu6616) Divide the Stones 机智题
题意: 给你重量分别为1到n的n个石头,让你分成重量相等,数量也相等的k组,保证k是n的约数.问你能不能分配,如果能,输出具体的分配方案. 题解: 首先,如果1到n之和不能整除k,那么一定不能如题意分 ...
- 大数据和BI商业智能有何区别?有何相关
大数据和BI商业智能有何区别?有何相关 大数据 ≠BI商业智能,大数据也不是传统商业智能的简单升级. 1.大数据和BI两者的区别 BI(BusinessIntelligence)即商业智能,它是企业数 ...
- Docker系列(五):Docker网络机制(上)
Linux路由机制打通网络 路由机制是效率最好的 docker128上修改Docker0的网络地址,与docker130不冲突 vi /usr/lib/systemd/system/docker.se ...