LOJ 2546 「JSOI2018」潜入行动——树形DP
题目:https://loj.ac/problem/2546
dp[ i ][ j ][ 0/1 ][ 0/1 ] 表示 i 子树,用 j 个点,是否用 i , i 是否被覆盖。
注意 s1<=s0 ,别弄出负角标。
用 if 判断一下,如果有值再转移,会快非常多。
复杂度是 O(n*k) 的。证明:https://www.cnblogs.com/cjyyb/p/10416839.html
先约定如果一个小于 k 的子树和一个大于 k 的子树合并,在小于 k 的子树那里看复杂度。
1.两个小于 k 的子树 cr 和 v 合并,且合并完之后还是小于 k 的;
对于 cr 里的每个点,要和 v 的每个点产生贡献。虽然和很多 v 都这样做了,但这些 v 的大小加起来小于 k (因为规定合并完还是小于 k ),所以一个点贡献 O(k) 次。
如果合并完大于 k ,就在 “一个小于 k 的子树和一个大于 k 的子树合并” 的部分考虑复杂度了。
2.一个小于 k 的子树 cr 和一个大于 k 的子树 v 合并。
对于 cr 里的每个点,此时都要进行 O(k) 次贡献。合并完之后 cr 的大小变成大于 k ,所以这种贡献,每个点只会经历一次。
3.一个大于 k 的子树 cr 和一个大于 k 的子树 v 合并。
产生 k2 的贡献。如果是两个大小为 k 的子树,合并之后大小变成 2*k ;再合并进来一个大小为 k 的,大小就变成 3*k ;即这种合并最多 \( \frac{n}{k} \) 次。
综上,复杂度是 O(n*k) 的。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
int Mx(int a,int b){return a>b?a:b;}
int Mn(int a,int b){return a<b?a:b;}
const int N=1e5+,M=,mod=1e9+;
int upt(int x){while(x>=mod)x-=mod;while(x<)x+=mod;return x;} int n,k,hd[N],xnt,to[N<<],nxt[N<<];
int siz[N],dp[N][M][][],tp[][];
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
void cz(int &x,int y){x=upt(x+y);}
void dfs(int cr,int fa)
{
dp[cr][][][]=dp[cr][][][]=; siz[cr]=;
for(int i=hd[cr],v;i;i=nxt[i])
if((v=to[i])!=fa)
{
dfs(v,cr);
for(int s0=Mn(k,siz[cr]+siz[v]);s0>=;s0--)
{
tp[][]=tp[][]=tp[][]=tp[][]=;
for(int s1=Mx(,s0-siz[cr]),lm=Mn(s0,Mn(siz[v],k));s1<=lm;s1++)
{
int d=s0-s1;
if(dp[cr][d][][])
{
cz(tp[][],(ll)dp[cr][d][][]*dp[v][s1][][]%mod);
cz(tp[][],(ll)dp[cr][d][][]*dp[v][s1][][]%mod);
}
if(dp[cr][d][][])
cz(tp[][],(ll)dp[cr][d][][]*(dp[v][s1][][]+dp[v][s1][][])%mod);
if(dp[cr][d][][])
{
cz(tp[][],(ll)dp[cr][d][][]*(dp[v][s1][][]+dp[v][s1][][])%mod);
cz(tp[][],(ll)dp[cr][d][][]*(dp[v][s1][][]+dp[v][s1][][])%mod);
}
if(dp[cr][d][][])
{
cz(tp[][],(ll)dp[cr][d][][]
*((ll)dp[v][s1][][]+dp[v][s1][][]+dp[v][s1][][]+dp[v][s1][][])%mod);
}
}
for(int f0=;f0<=;f0++)
for(int f1=;f1<=;f1++)
dp[cr][s0][f0][f1]=tp[f0][f1];
}
siz[cr]+=siz[v];
}
}
int main()
{
n=rdn();k=rdn();
for(int i=,u,v;i<n;i++)
u=rdn(),v=rdn(),add(u,v),add(v,u);
dfs(,);
printf("%d\n",upt(dp[][k][][]+dp[][k][][]));
return ;
}
LOJ 2546 「JSOI2018」潜入行动——树形DP的更多相关文章
- 【LOJ】#2546. 「JSOI2018」潜入行动
题解 dp[i][j][0/1][0/1]表示以\(i\)为根的子树,用了\(j\)个,i点选了或者没选,i点被覆盖或没被覆盖 转移比较显然,但是复杂度感觉不太对? 其实转移到100个的时候就使第二维 ...
- LOJ 2550 「JSOI2018」机器人——找规律+DP
题目:https://loj.ac/problem/2550 只会写20分的搜索…… #include<cstdio> #include<cstring> #include&l ...
- LOJ 2548 「JSOI2018」绝地反击 ——二分图匹配+网络流手动退流
题目:https://loj.ac/problem/2548 如果知道正多边形的顶点,就是二分答案.二分图匹配.于是写了个暴力枚举多边形顶点的,还很愚蠢地把第一个顶点枚举到 2*pi ,其实只要 \( ...
- LOJ 2551 「JSOI2018」列队——主席树+二分
题目:https://loj.ac/problem/2551 答案是排序后依次走到 K ~ K+r-l . 想维护一个区间排序后的结果,使得可以在上面二分.求和:二分可以知道贡献是正还是负. 于是想用 ...
- LOJ 2547 「JSOI2018」防御网络——思路+环DP
题目:https://loj.ac/problem/2547 一条树边 cr->v 会被计算 ( n-siz[v] ) * siz[v] 次.一条环边会被计算几次呢?于是去写了斯坦纳树. #in ...
- LG4516/LOJ2546 「JSOI2018」潜入行动 树上背包
问题描述 LG4516 LOJ2546 题解 好一个毒瘤题. hkk:JSOI的签到题 设\(opt[i][j][0/1][0/1]\)代表结点\(i\)的子树,放置\(j\)个,\(i\)放不放,\ ...
- LOJ 3092 「BJOI2019」排兵布阵 ——DP
题目:https://loj.ac/problem/3092 同一个人的不同城堡之间没有什么联系,只是和<=m.所以对每个城堡的 s 个值排序,做一个 f[ i ][ j ] 表示第 i 个城堡 ...
- LG1131 「ZJOI2007」时态同步 树形DP
问题描述 LG1131 题解 正难则反,把从一个点出发到叶子结点看做从叶子结点走到那个点. DP方程很显然. \(\mathrm{Code}\) #include<bits/stdc++.h&g ...
- Loj #2192. 「SHOI2014」概率充电器
Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...
随机推荐
- gevent-协程用法
文章介绍了一种采用循环的方式生产协程列表,并可以向协程函数传递参数... # 协程引用import gevent from gevent import monkey, pool monkey.patc ...
- 由装饰者模式来深入理解Java I/O整体框架
前言 Java里面的I/O这一部分看过很多遍,每次看完之后特别混乱,又是输入流,又是输出流,又是字符流,又是字节流,还有什么过滤流,缓冲流.每次看得我如入云里雾里,直到后面看了设计模式这一块,才算真正 ...
- CentOS7.5 Python3安装pip报错:ModuleNotFoundError: No module named '_ctypes' --Python3
1.问题:pyhontModuleNotFoundError: No module named '_ctypes' 操作系统:CentOS7.5 安装完Pyhotn3后(如何安装Python3,安装 ...
- 图论++【洛谷p1744】特价采购商品&&【一本通1342】最短路径问题
(虽然题面不是很一样,但是其实是一个题qwq) [传送门] 算法标签: 利用Floyed的o(n3)算法: (讲白了就是暴算qwq) 从任意一条单边路径开始.所有两点之间的距离是边的权,或者无穷大,如 ...
- c++中的c_str()用法
语法: const char *c_str(); c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同. 这是为了与c语言兼容,在c语言中没有string类型,故必须通过st ...
- mysql 5.7版本的安装(非解压版)
这次的开发项目数据库方面要用到mysql,为了更好的学习,就在本地安装了一个mysql 一:下载安装步骤: https://blog.csdn.net/qq_34952973/article/deta ...
- 使用VUE框架搭建项目基本步骤
ps:初入Vue坑的小伙伴们,对于独立做一个项目可能不清楚需要使用哪些资源,这篇随笔希望对大家有所帮助. 第一步:参照vue的官方文档,建立一个vue的项目 # 全局安装 vue-cli $ npm ...
- 洛谷P1030求先序排列
题目描述 给出一棵二叉树的中序与后序排列.求出它的先序排列.(约定树结点用不同的大写字母表示,长度≤8. 输入输出格式 输入格式: 2行,均为大写字母组成的字符串,表示一棵二叉树的中序与后序排列. 输 ...
- Chained Exceptions in Java
1. Overview In this article, we’ll have a very brief look at what Exception is and go in depth about ...
- java使用StringBuilder的方法反转字符串输出
public class FanZhuan { public static void main(String[] args) { /**第一种方法*/ String s = "9876543 ...