ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【题解 LOJ2546「JSOI2018」潜入行动】

2020-05-14 21:07:37  阅读:258  来源: 互联网

标签:LOJ2546 覆盖 JSOI2018 题解 ll times int 安装 hd


部分分:

\(\texttt{Subtask1 10pts }n\le 20\)

枚举每个点装不装监听器,然后判断是否可行

\(\texttt{Subtask2 10pts }k\le 10\)

\(k\) 很小,在随机情况下(也同样是数据)无法覆盖整个树,直接输出 \(0\)。

\(\texttt{Subtask3 10pts }\) 整个树是链

如果 \(k\) 小于 \(n-2\),那么无法覆盖住这个树,输出 \(0\)

所以如果我在考场上可以拿 \(30\) 分……


正解:

显然这是个树形背包,我们可以用树形背包的常见套路做。\(f(u,x,0/1,0/1)\) 代表第 \(u\) 个节点子树用 \(x\) 个监听器,\(u\) 装/不装监听器,\(u\)有/没有被覆盖。

(以下 \(v\) 代表 \(u\) 的儿子)


对于 \(f(u,x,0,0)\),由于自己不能被覆盖,所以 \(v\) 就不能安装。由于自己不能安装,所以 \(v\) 一定需要安装(否则就没有其他人去覆盖这个节点了)。

由于这个是乘法原理算种类数,所以应该是乘起来。

\[f(u,i+j,0,0)=f(u,i,0,0)\times f(v,j,0,1) \]

对于 \(f(u,x,0,1)\),由于自己被覆盖,所以 \(v\) 中至少有一个必须安装。

那么可以转移到这个状态的 \(f(u)\) 应该有 \(f(u,x,0,0)\) 和 \(f(u,x,0,1)\),可以显然推得:

\[f(u,i+j,0,1)=f(u,i,0,0)\times f(v,j,1,1)+f(u,i,0,1)\times f(v,j,0/1,1) \]

对于 \(f(u,x,1,0)\),由于自己没有被覆盖,所以 \(v\) 就不能安装。由于自己安装了,所以 \(v\) 可以覆盖或者不覆盖。

\[f(u,i+j,1,0)=f(u,i,1,0)\times f(v,j,0,0/1) \]

对于 \(f(u,x,1,1)\),由于自己被覆盖了,所以 \(v\) 中至少有一个安装。可以转移到这个状态的 \(f(u)\) 有 \(f(u,x,1,0)\) 和 \(f(u,x,1,1)\)。

由于自己安装了,所 \(v\) 可以覆盖或者不覆盖。

\[f(u,i+j,1,1)=f(u,i,1,0)\times f(v,j,1,0/1)+f(u,i,1,1)\times f(v,j,0/1,0/1) \]

初始化: \(f(u,0,0,0)=f(u,1,1,0)=1\)


代码&细节

推完式子就可以写代码了(转移方程长得有点难受)。

然后这题强制用 int 然后操作转 longlong 很杀人。

我对出题人卡空间的行为感到非常不满

foin(x,y) 函数代表两数相加并取模(在 int 转 longlong 操作中很实用)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+3; const ll mod=1000000007;
struct edge{int to,nxt;}e[N*2]; int hd[N],tot;
void add(int u,int v){e[++tot]=(edge){v,hd[u]},hd[u]=tot;}
int n,k;
int foin(ll q,ll p){return (q+p)>mod?1ll*q+p-mod:q+p;}

int sz[N],f[N][103][2][2],t[103][2][2]; //树形背包常用的3个数组
void dfs(int u,int fa){
	f[u][0][0][0]=f[u][1][1][0]=sz[u]=1;
	for(register int p=hd[u],v;p;p=e[p].nxt)
		if((v=e[p].to)!=fa){
			dfs(v,u);
			for(register int i=0;i<=min(sz[u],k);i++)
				for(register int j=0;j<2;j++)
					for(register int k=0;k<2;k++)
						t[i][j][k]=f[u][i][j][k], f[u][i][j][k]=0;
			for(register int i=0;i<=min(sz[u],k);i++){
				for(register int j=0;j<=min(sz[v],k-i);j++){
					f[u][i+j][0][0]=foin(f[u][i+j][0][0],1ll*t[i][0][0]*f[v][j][0][1]%mod);
					f[u][i+j][0][1]=foin(f[u][i+j][0][1],(1ll*t[i][0][0]*f[v][j][1][1]+1ll*t[i][0][1]*(1ll*f[v][j][0][1]+f[v][j][1][1]))%mod);
					f[u][i+j][1][0]=foin(f[u][i+j][1][0],1ll*t[i][1][0]*(1ll*f[v][j][0][0]+f[v][j][0][1])%mod);
					f[u][i+j][1][1]=foin(f[u][i+j][1][1],foin((1ll*t[i][1][0]*(1ll*f[v][j][1][0]+f[v][j][1][1])%mod)
						,1ll*t[i][1][1]*(1ll*f[v][j][0][0]+f[v][j][0][1]+f[v][j][1][0]+f[v][j][1][1])%mod));
				}
			}
			sz[u]+=sz[v];
		}
}

int main(){
	scanf("%d%d",&n,&k);
	for(int i=1,u,v;i<n;i++)
		scanf("%d%d",&u,&v),add(u,v),add(v,u);
	dfs(1,0);
	printf("%lld",1ll*(f[1][k][0][1]+f[1][k][1][1])%mod);
	return 0;
}

标签:LOJ2546,覆盖,JSOI2018,题解,ll,times,int,安装,hd
来源: https://www.cnblogs.com/TetrisCandy/p/12891328.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有