博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ5314:[JSOI2018]潜入行动——题解
阅读量:6604 次
发布时间:2019-06-24

本文共 2260 字,大约阅读时间需要 7 分钟。

外星人又双叒叕要攻打地球了,外星母舰已经向地球航行!这一次,JYY已经联系好了黄金舰队,打算联合所有JSOIer抵御外星人的进攻。在黄金舰队就位之前,JYY打算事先了解外星人的进攻计划。现在,携带了监听设备的特工已经秘密潜入了外星人的母舰,准备对外星人的通信实施监听。外星人的母舰可以看成是一棵n个节点、n-1条边的无向树,树上的节点用1,2...n编号。JYY的特工已经装备了隐形模块,可以在外星人母舰中不受限制地活动,可以神不知鬼不觉地在节点上安装监听设备。如果在节点u安装监听设备,则JYY能够监听与u直接相邻所有的节点的通信。换言之,如果在节点u安装监听设备,则对于树中每一条边(u,v),节点v都会被监听。特别注意放置在节点u的监听设备并不监听u本身的通信,这是JYY特别为了防止外星人察觉部署的战术。
 
 JYY的特工一共携带了k个监听设备,现在JYY想知道,有多少种不同的放置监听设备的方法,能够使得母舰上所有节点的通信都被监听?为了避免浪费,每个节点至多只能安装一个监听设备,且监听设备必须被用完。

一个很好想的dp[i][j][0/1][0/1]表示i为根的子树放了j个设备,i结点没放/放了设备,i结点没被控制/控制。

然后就是惊天地泣鬼神的转移了,看代码应该能看懂吧,我们其实就是把每棵子树按照乘法原理依次加入即可。

难还真不难,但是dp式子真心长,还卡你常,你就没话说了(虽然最坏复杂度是O(nkk)的但是显然达不到,而且这种树形dp依赖每棵子树更新的话应该是有O(nk)做法的。)

UPD:听说这个复杂度就是O(nk)的?然而网上的证明并没有看懂……

#include
#include
#include
#include
#include
#include
#include
using namespace std;typedef long long ll;const int p=1e9+7;const int N=1e5+5;const int K=105;inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X;}struct node{ int to,nxt;}e[N*2];int n,k,cnt,head[N],size[N];int f[N][K][2][2],g[K][2][2];inline void ins(int u,int v){ e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;}inline void add(int &x,ll y){ x+=y%p; if(x>=p)x-=p;}void dfs(int u,int fa){ size[u]=1; f[u][0][0][0]=f[u][1][1][0]=1; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if(v==fa)continue; dfs(v,u); for(int i=0,l1=min(k,size[u]);i<=l1;i++){ g[i][0][0]=f[u][i][0][0];f[u][i][0][0]=0; g[i][0][1]=f[u][i][0][1];f[u][i][0][1]=0; g[i][1][0]=f[u][i][1][0];f[u][i][1][0]=0; g[i][1][1]=f[u][i][1][1];f[u][i][1][1]=0; } for(int i=0,l1=min(k,size[u]);i<=l1;i++){ for(int j=0,l2=min(k-i,size[v]);j<=l2;j++){ add(f[u][i+j][0][0],(ll)g[i][0][0]*f[v][j][0][1]); add(f[u][i+j][0][1],(ll)g[i][0][1]*(f[v][j][0][1]+f[v][j][1][1])+(ll)g[i][0][0]*f[v][j][1][1]); add(f[u][i+j][1][0],(ll)g[i][1][0]*(f[v][j][0][0]+f[v][j][0][1])); add(f[u][i+j][1][1],(ll)g[i][1][1]*((ll)f[v][j][0][0]+f[v][j][0][1]+f[v][j][1][0]+f[v][j][1][1])+(ll)g[i][1][0]*(f[v][j][1][0]+f[v][j][1][1])); } } size[u]+=size[v]; }}int main(){ n=read(),k=read(); for(int i=1;i

 

转载于:https://www.cnblogs.com/luyouqi233/p/9085654.html

你可能感兴趣的文章
CMD命令行基本命令
查看>>
Go语言的通道(2)-缓冲通道
查看>>
javascript 正则表达式邮箱验证
查看>>
poj1328
查看>>
response.write()跟ajax冲突的解决方案
查看>>
【编码】utf-8
查看>>
两个viewport的故事(第二部分)
查看>>
display:table-cell的应用
查看>>
在micropython固件中增加自己的模块
查看>>
【数学】数论进阶-常见数论函数
查看>>
第一轮复习Servlet day04
查看>>
Babel下的ES6兼容性与规范
查看>>
【iOS开发】视图控制器加载和卸载时的几个函数
查看>>
python——装饰器
查看>>
事件的绑定
查看>>
.htaccess内容
查看>>
关于表单重复提交问题
查看>>
port 22: Connection refused
查看>>
java中关键字volatile的作用(转载)
查看>>
基础查询语句
查看>>