【vijos】1892 树上的最大匹配(树形dp+计数)
这个必须得卡评测机+手动开栈才能卡过QAQ
手动开栈我百度的。。。
int size=256<<20; //256MB
char *p=(char*)malloc(size)+size;
__asm__("movl %0, %%esp\n" :: "r"(p));
然后我交了无数发,然后才卡过。。。。
我们设状态
f[i][0]表示i节点与儿子的边一个也不选
f[i][1]表示i节点只选一条与儿子的边
g[i][0]和g[i][1]对应方案
那么转移就是
f[i][0]=sigma{max{f[j][0], f[j][1]} j是i的儿子}
f[i][1]=max{f[j][0]+sigma{max{f[k][0], f[k][1]}} j和k都是i的儿子,j!=k }
方案的话同理
这样能做到不重不漏。。。
后者我们用前缀和和后缀和维护。。。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
#define mkpii make_pair<int, int>
#define pdi pair<double, int>
#define mkpdi make_pair<double, int>
#define pli pair<ll, int>
#define mkpli make_pair<ll, int>
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define read(a) a=getint()
#define print(a) printf("%d", a)
#define dbg(x) cout << (#x) << " = " << (x) << endl
#define error(x) (!(x)?puts("error"):0)
#define printarr2(a, b, c) for1(_, 1, b) { rep(__, c) cout << a[_][__] << '\t'; cout << endl; }
#define printarr1(a, b) for1(_, 1, b) cout << a[_] << '\t'; cout << endl
inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
inline const int max(const int &a, const int &b) { return a>b?a:b; }
inline const int min(const int &a, const int &b) { return a<b?a:b; } const int N=2000005;
int ihead[N], cnt, n, f[N][2], st[N], r[N];
ll MD, sumr[N], d[N][2];
struct ED { int next, to; }e[N<<1];
void add(int u, int v) {
e[++cnt].next=ihead[u]; ihead[u]=cnt; e[cnt].to=v;
e[++cnt].next=ihead[v]; ihead[v]=cnt; e[cnt].to=u;
}
void dp(int x, int fa) {
int t0=0; ll s0=1;
for(int i=ihead[x]; i; i=e[i].next) if(e[i].to!=fa) {
int y=e[i].to;
dp(y, x);
int mx=max(f[y][0], f[y][1]); ll tp=0;
if(f[y][0]==mx) tp+=d[y][0];
if(f[y][1]==mx) tp+=d[y][1];
s0=(s0*tp)%MD;
t0+=mx;
}
f[x][0]=t0;
d[x][0]=s0;
int sz=0, l=0; ll suml=1;
for(int i=ihead[x]; i; i=e[i].next) if(e[i].to!=fa) st[++sz]=e[i].to;
sumr[sz+1]=1; r[sz+1]=0;
for3(i, sz, 1) {
int mx=max(f[st[i]][0], f[st[i]][1]); ll tp=0;
if(mx==f[st[i]][0]) tp+=d[st[i]][0];
if(mx==f[st[i]][1]) tp+=d[st[i]][1];
r[i]=r[i+1]+mx;
sumr[i]=(sumr[i+1]*tp)%MD;
}
f[x][1]=-N;
for1(i, 1, sz) {
int tp=l+f[st[i]][0]+r[i+1]+1;
if(tp>f[x][1]) {
f[x][1]=tp;
d[x][1]=(d[st[i]][0]*((suml*sumr[i+1])%MD))%MD;
}
else if(tp==f[x][1]) {
d[x][1]=d[x][1]+(d[st[i]][0]*((suml*sumr[i+1])%MD))%MD;
}
int mx=max(f[st[i]][0], f[st[i]][1]); s0=0;
if(mx==f[st[i]][0]) s0+=d[st[i]][0];
if(mx==f[st[i]][1]) s0+=d[st[i]][1];
suml=(suml*s0)%MD;
l+=mx;
}
} int main() {
int size=256<<20;
char *p=(char*)malloc(size)+size;
__asm__("movl %0, %%esp\n" :: "r"(p));
read(n);
for1(i, 1, n-1) add(getint(), getint());
read(MD);
int root=(n+1)>>1;
dp(root, -1);
int ans1=max(f[root][0], f[root][1]); ll ans2=0;
if(ans1==f[root][0]) ans2+=d[root][0];
if(ans1==f[root][1]) ans2+=d[root][1];
printf("%d\n%lld\n", ans1, ans2%MD);
return 0;
}
然后就行了。。
描述
doc 的学姐曾经也是一名 oier, 她有的时候会询问 doc 各种有趣的竞赛问题
虽然很简单, 但是对于 doc 来说都是曾经很美好的回忆
今天, 学姐不想出去逛街, 因为她看到了一道题目并为此发愁在.
树上的最大匹配是多少? 最大匹配解的方案共有多少组?
(首先树可以被看作是一个无向图G.
(对于无向图G来说, 其上的最大匹配是边集的一个子集, 满足:
(对于G中每一个点来说, 都只有最多一条与之相连的边在这个子集中.
(最大匹配就是这个子集大小可以到达的最大值.
格式
输入格式
第一行输入一个整数 n, 表示树上的结点个数. 所有结点依次编号为 1 到 n.
之后 n-1 行, 每行有两个整数 a , b 表示有一条链接结点 a 和 b的边.
最后一行有一个整数 m, 表明对于最大匹配解的方案, 我们只需要输出对 m 取的余数.
输出格式
第一行有一个整数, 表示最大匹配有多大.
第二行有一个整数, 表示对 m 取余后的方案总数.
限制
对于30%的数据, n<=2500.
对于70%的数据, n<=100,000.
对于100%的数据, n<=1,500,000.
m为32位有符号整数
【vijos】1892 树上的最大匹配(树形dp+计数)的更多相关文章
- Vijos p1892 树上的最大匹配 树形DP+计数 被卡常我有特殊技巧heheda
https://vijos.org/p/1892 此题需要手动开栈: <<; //256MB char *p=(char*)malloc(size)+size; __asm__(" ...
- 【vijos】1770 大内密探(树形dp+计数)
https://vijos.org/p/1770 不重不漏地设计状态才能正确的计数QAQ 虽然可能最优化是正确的,但是不能保证状态不相交就是作死.... 之前设的状态错了... 应该设 f[i][0] ...
- BZOJ_4033_[HAOI2015]树上染色_树形DP
BZOJ_4033_[HAOI2015]树上染色_树形DP Description 有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并 将其他的 ...
- 2021.07.17 P3177 树上染色(树形DP)
2021.07.17 P3177 树上染色(树形DP) [P3177 HAOI2015]树上染色 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 重点: 1.dp思想是需要什么,维护 ...
- Vijos p1770 大内密探 树形DP+计数
4天终于做出来了,没错我就是这么蒟蒻.教训还是很多的. 建议大家以后编树形DP不要用记忆化搜索,回溯转移状态个人感觉更有条理性. 大神题解传送门 by iwtwiioi 我的题解大家可以看注释&quo ...
- 树上的等差数列 [树形dp]
树上的等差数列 题目描述 给定一棵包含 \(N\) 个节点的无根树,节点编号 \(1\to N\) .其中每个节点都具有一个权值,第 \(i\) 个节点的权值是 \(A_i\) . 小 \(Hi\) ...
- [vijos 1642]班长的任务 [树形dp]
背景 十八居士的毕业典礼(1) 描述 福州时代中学2009届十班同学毕业了,于是班长PRT开始筹办毕业晚会,但是由于条件有限,可能每个同学不能都去,但每个人都有一个权值,PRT希望来的同学们的权值总和 ...
- 【BZOJ4033】[HAOI2015] 树上染色(树形DP)
点此看题面 大致题意: 给你一棵点数为N的带权树,要你在这棵树中选择K个点染成黑色,并将其他的N-K个点染成白色.要求你求出黑点两两之间的距离加上白点两两之间距离的和的最大值. 树形\(DP\) 这道 ...
- Codeforces Round #277 (Div. 2)D(树形DP计数类)
D. Valid Sets time limit per test 1 second memory limit per test 256 megabytes input standard input ...
随机推荐
- 倍福TwinCAT(贝福Beckhoff)常见问题(FAQ)-如何在程序中添加注释
在TwinCAT2中,(*中间输入注释*),也可以用这种方法批量注释,在TwinCAT3中,使用//即可 更多教学视频和资料下载,欢迎关注以下信息: 我的优酷空间: http://i.youk ...
- 1、jQuery概述
JQuery基本功能 ① 访问和操作Dom元素 ② 控制页面样式 ③ 对页面事件的处理 ④ 大量插件在页面中的运用 ⑤ 与Ajax技术的完美结合 $(document).ready ...
- 批量将代码中的 get_XXX 替换成 XXX
使用 sed 只需要一个命令: sed -s -i 's/set_\([A-Za-z0-9_]*\)/\1 = /g' ` find . -name '*.cs' | xargs grep -l se ...
- STL源码剖析(deque)
deque是一个双向开口的容器,在头尾两端进行元素的插入跟删除操作都有理想的时间复杂度. deque使用的是分段连续线性空间,它维护一个指针数组(T** map),其中每个指针指向一块连续线性空间. ...
- CentOS忘记root密码解决办法
如果是忘记普通的用户密码,那还好说,用root登录命令行界面,修改即可. 但如果是root的话,那就需要这样修改了. 记住,这几篇文章说的都是对的,只是我复杂了,实际只需要将光标移到最后" ...
- QT Unexpected CDB exit 问题的解决办法
行QT进行debug时,提示 Unexpected CDB exit ,The CBD process terminated.. QtCreator 默认是没有调试器的,因此需要用户额外安装. win ...
- Android横竖屏布局总结
Android横竖屏要解决的问题应该就两个:一.布局问题;二.重新载入问题. 1.布局问题:如果不想让软件在横竖屏之间切换,最简单的办法就是在项目的 AndroidManifest.xml中找到你 ...
- CentOs 7 安装总结
1.安装 前几天安装了CentOs 7系统,弄了好几次都进不去图形安装界面,总是进入 "dracut:/# _".本以为是系统盘没做好,就用了另外几种工具重做了盘,还是一样.后来在 ...
- 如何设置UITextView不可被编辑
在项目中遇到一些需求需要把文字用UITextView来展示,但是该文字不能被编辑,只要把以下该代理方法实现就可以了 -(BOOL)textViewShouldBeginEditing:(UITextV ...
- lua工具库penlight--07函数编程(一)
函数编程 序列 Lua 迭代器 (最简单的形式) 是一个函数,可以多次调用返回一个或多个值.for in语句理解迭代器和循环,直到该函数将返回nil. Lua有标准的序列迭代器 (ipairs和pai ...