zoukankan      html  css  js  c++  java
  • 【题解 LOJ2546「JSOI2018」潜入行动】

    部分分:

    ( exttt{Subtask1 10pts }nle 20)

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

    ( exttt{Subtask2 10pts }kle 10)

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

    ( exttt{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) imes 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) imes f(v,j,1,1)+f(u,i,0,1) imes f(v,j,0/1,1) ]

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

    [f(u,i+j,1,0)=f(u,i,1,0) imes 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) imes f(v,j,1,0/1)+f(u,i,1,1) imes 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;
    }
    
  • 相关阅读:
    混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该程序集。
    SQL中获取自增长的最大ID
    (inline)内联函数在IOS开发中的使用
    MS SQL SERVER 2005 高可用性之日志传送
    19_toast通知和notify通知 onTouch事件响应
    20 按比例设置 子控件的宽度和高度
    18_SurfaceView 其他线程绘图
    使用Microsoft Media Service实现网络影音多媒体应用系列第三篇技术要点
    使用Microsoft Media Service实现网络影音多媒体应用系列第二篇开发须知
    MVC3WIN7下的IIS7.5部署MVC3应用程序
  • 原文地址:https://www.cnblogs.com/TetrisCandy/p/12891328.html
Copyright © 2011-2022 走看看