【vijos】1770 大内密探(树形dp+计数)
不重不漏地设计状态才能正确的计数QAQ
虽然可能最优化是正确的,但是不能保证状态不相交就是作死。。。。
之前设的状态错了。。。
应该设
f[i][0]表示i点不取且至少有一个儿子取,且保证i点被覆盖
f[i][1]表示i点取儿子任意,且保证i点被覆盖
f[i][2]表示i点不取且i点的儿子也不取,保证i点不被覆盖!(即留给父亲覆盖)
f[i][2]表示i点不取且儿子也不取。并不是表示i点不取儿子任意!!!!!!!!!!要不然这样会出现交的情况!假设使用后者,那么就会产生和f[i][0]一样的状态!!!!!!
然后我们分别计数
g[i][0]表示f[i][0]的方案数,g[i][1]表示f[i][1]的方案数,g[i][2]表示f[i][2]的方案数,那么有初始化
g[i][0]=0 当i没有儿子时
而转移f[i][1]和f[i][2]很简单,即
f[i][1]=sigma{ min{f[j][0], f[j][1], f[j][2]} (j是i儿子) }
f[i][2]=sigma{ f[j][0] (j是i儿子) }
方案的话加法乘法原理上。。。
f[i][0]转移非常麻烦(因为还要顾及到g[i][0],要做到不重不漏!)
首先我们知道,至少要有一个儿子选中状态才能转移。
如果不小心,很容易得到
f[i][0]=min{f[j][1]+sigma{min{f[k][0], f[k][1]}} (j和k均为i儿子且j!=k) }
这样虽然可以用技巧实现O(n)转移,但是方案却不能够得到!
比如i有2和3这两个儿子,f[3][0]=5, f[3][1]=3, f[2][0]=6, f[2][1]=3;那么转移的时候,两次决策都是f[2][1]+f[3][1]或f[3][1]+f[2][1]!!!!!这样显然不能计数。。重合了。。
所以我之前就这样sb了。。
那么我们考虑如何去重?我们分析得到,我们枚举要取的儿子时,之前枚举过的全部给取f[k][0],没有取过的任意!!!!这样就不会重!
那么问题就好解决了,我们在枚举儿子时,维护一个前缀和f[k][0],k是已经枚举过的,然后再维护一个后缀和,表示sum{min{f[l][0], f[l][1]}},l是未枚举过的
计数的方法相同,那么问题就解决了orz
#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; }
#define rdm(x,i) for(int i=ihead[x]; i; i=e[i].next) const int N=100005, oo=~0u>>1, MD=1000000007;
int ihead[N], cnt, n, f[N][3], l, r[N], st[N];
ll d[N][3], suml, sumr[N];
struct ED { int to, next; }e[N<<1];
ll mul(ll a, ll b) { return ((a%MD)*(b%MD))%MD;}
ll Plus(ll a, ll b) { return ((a%MD)+(b%MD))%MD;}
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 dfs(int x, int fa) {
int t1=1, t2=0, s1=1, s2=1, y;
rdm(x, i) if((y=e[i].to)!=fa) {
ll tp=0;
dfs(y, x);
int mn=min(min(f[y][0], f[y][1]), f[y][2]); if(f[y][0]==mn) tp+=d[y][0];
if(f[y][1]==mn) tp+=d[y][1];
if(f[y][2]==mn) tp+=d[y][2];
s1=mul(s1, tp); tp=0;
s2=mul(s2, d[y][0]); t1+=mn;
t2+=f[y][0];
}
f[x][1]=t1;
f[x][2]=t2; d[x][1]=s1;
d[x][2]=s2; int sz=0;
rdm(x, i) if(e[i].to!=fa) st[++sz]=e[i].to;
r[sz+1]=0; sumr[sz+1]=1; suml=1; l=0;
for3(i, sz, 1) {
y=st[i];
int mn=min(f[y][0], f[y][1]); ll tp=0;
if(f[y][0]==mn) tp+=d[y][0];
if(f[y][1]==mn) tp+=d[y][1];
r[i]=r[i+1]+mn;
sumr[i]=mul(sumr[i+1], tp);
}
f[x][0]=N;
for1(i, 1, sz) {
if(l+f[st[i]][1]+r[i+1]<f[x][0]) {
f[x][0]=l+f[st[i]][1]+r[i+1];
d[x][0]=mul(d[st[i]][1], mul(suml, sumr[i+1]));
}
else if(l+f[st[i]][1]+r[i+1]==f[x][0]) {
d[x][0]=Plus(d[x][0], mul(d[st[i]][1], mul(suml, sumr[i+1])));
}
if(f[st[i]][0]==N) break;
l+=f[st[i]][0];
suml=mul(suml, d[st[i]][0]);
}
}
int main() {
read(n);
for1(i, 1, n-1) add(getint(), getint());
int root=1;
dfs(root, -1);
int ans1=min(f[root][1], f[root][0]), ans2=0;
if(ans1==f[root][0]) ans2=Plus(ans2, d[root][0]);
if(ans1==f[root][1]) ans2=Plus(ans2, d[root][1]);
printf("%d\n%d\n", ans1, ans2);
return 0;
}
背景
大内密探,负责秘密保护皇上,还有保护皇宫内外一切产业。——大内密探零零七
描述
在古老的皇宫中,有N个房间以及N-1条双向通道,每条通道连接着两个不同的房间,所有的房间都能互相到达。皇宫中有许多的宝物,所以需要若干个大内密探来守护。一个房间被守护当切仅当该房间内有一名大内密探或者与该房间直接相邻的房间内有大内密探。
现在身为大内密探零零七的你想知道要把整个皇宫守护好至少需要多少名大内密探以及有多少种安排密探的方案。两种方案不同当且仅当某个房间在一种方案有密探而在另一个方案内没有密探。
格式
输入格式
第一行一个正整数N.(1<=N<=100000)
后面N-1行,每行两个正整数a和b,表示房间a和房间b之间有一条无向通道。
房间的编号从1到N
输出格式
第一行输出正整数K,表示最少安排的大内密探。
第二行输出整数S,表示有多少种方案安排最少的密探,由于结果可能较大,请输出方案数mod 1000000007的余数。
限制
每个测试点1s
提示
30%保证:n <= 10
70%保证:n <= 1000
100%保证:n <= 100000
【vijos】1770 大内密探(树形dp+计数)的更多相关文章
- Vijos p1770 大内密探 树形DP+计数
4天终于做出来了,没错我就是这么蒟蒻.教训还是很多的. 建议大家以后编树形DP不要用记忆化搜索,回溯转移状态个人感觉更有条理性. 大神题解传送门 by iwtwiioi 我的题解大家可以看注释&quo ...
- [vijos 1770]大内密探
描述 在古老的皇宫中,有N个房间以及N-1条双向通道,每条通道连接着两个不同的房间,所有的房间都能互相到达.皇宫中有许多的宝物,所以需要若干个大内密探来守护.一个房间被守护当切仅当该房间内有一名大内密 ...
- Vijos p1518河流 树形DP
https://vijos.org/p/1518 这题代码我基本是抄的,实在太难想了.但是也学到了一些东西. 比如:多叉树转二叉树存,这个细细一想,确实使得在dfs的时候,实现起来方便很多. 说一说具 ...
- vijos 1180 选课 树形DP
描述 学校实行学分制.每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分.学校开设了N(N<300)门的选修课程,每个学生可选课程的数量M是给定的.学生选修了这M门课并考核通过就能获得 ...
- 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 ...
- Vijos p1892 树上的最大匹配 树形DP+计数 被卡常我有特殊技巧heheda
https://vijos.org/p/1892 此题需要手动开栈: <<; //256MB char *p=(char*)malloc(size)+size; __asm__(" ...
- 【vijos】1892 树上的最大匹配(树形dp+计数)
https://vijos.org/p/1892 这个必须得卡评测机+手动开栈才能卡过QAQ 手动开栈我百度的... int size=256<<20; //256MB char *p=( ...
- Tree Cutting (Hard Version) CodeForces - 1118F2 (树形DP,计数)
大意:给定树, 每个点有颜色, 一个合法的边集要满足删除这些边后, 每个连通块内颜色仅有一种, 求所有合法边集的个数 $f[x][0/1]$表示子树$x$中是否还有与$x$连通的颜色 对于每种颜色已经 ...
- 牛客第八场 C-counting paths 树形dp计数
题目地址 题意 给你一颗树 初始点颜色全部为白色 对于每一个满足要求一的点集s f(s)的定义为先把点集内的点染黑 满足要求二的路径集合数量 要求一为两两黑点之间不能出现白色的点 要求二为将这个路径集 ...
随机推荐
- mysql中,由于JDBC连接限制了最大包长度1024B,即1KB,报错“max_allowed_packet' ”
报错:org.springframework.dao.TransientDataAccessResourceException: PreparedStatementCallback; SQL [INS ...
- 苹果推送服务器端证书配置.pem生成
做苹果推送服务器,很重要的一步,就是生成与苹果APNS连接的证书,一般是.pem文件: 首先在苹果开发者中心 生成 aps_devlopment.cer文件:然后下载:双击导入钥匙串: 打开钥匙串 - ...
- vue项目中provide和inject的运用
类型: provide:Object | () => Object inject:Array<string> | { [key: string]: string | Symbol | ...
- Direcshow中视频捕捉和參数设置报告
Direcshow中视频捕捉和參数设置报告 1. 关于视频捕捉(About Video Capture in Dshow) 1视频捕捉Graph的构建 一个能够捕捉音频或者视频的graph图 ...
- 《深入浅出pig系列之中的一个》pig-0.12.0-cdh5.1.2的安装与执行
这里使用的版本号是cdh发行的pig-0.12.0-cdh5.1.2 下载地址点这里 1.Pig简单介绍: Pig是yahoo捐献给apache的一个项目.它是SQL-like语言.是在MapRedu ...
- AppIcon尺寸
- Windows最强ssh客户端推荐 —— Bitvise SSH Client
原名Tunnelier,解除它是因为为了sshFQ,没想到它既有SSH Terminal,又集成SFTP,还能FQ,功能一应区全. 还支持pem证书,回想最初使用putty,还要把pem证书进行转换才 ...
- web页面查看Tomcat服务器指标
在进行性能测试时,一般都需要对应用服务器进行监控,监控的指标包括应用服务器的JVM使用状况.可用连接数.队列长度等信息.商业的应用服务器如WebLogic.WebSphere等都提供了Console对 ...
- javascript Date日期类
四.Date日期类 迁移时间:2017年5月27日18:43:02 Author:Marydon (一)对日期进行格式化(日期转字符串) 自定义Date日期类的format()格式化方法 方式一: ...
- .Net程序员面试 中级篇 (回答Scott Hanselman的问题)
继<.Net 程序员面试 C# 语言篇 (回答Scott Hanselman的问题)>跟<.Net程序员面试 每个人都应知道篇 (回答Scott Hanselman的问题)>之 ...