• [JSOI2018]潜入行动


    [JSOI2018]潜入行动

    题目大意:

    一棵(n(nle10^5))个结点的树,在一些点上安装(k(klemin(n,100)))个装置。每个装置可以控制所有与安装位置相邻的结点(不包括本身)。每个点可以安装至多一个装置。问有多少种方案恰好用完(k)个装置,使得所有的结点都被控制。

    思路:

    树形DP。(f[i][j][0/1][0/1])表示以(i)为根的子树内安装了(j)个装置,(i)本身是否安装,(i)是否被控制。手动讨论转移:

    f[x][j+k][0][0]+=f[y][k][0][1]*g[j][0][0]
    f[x][j+k][0][1]+=f[y][k][0][1]*g[j][0][1]
    f[x][j+k][0][1]+=f[y][k][1][1]*g[j][0][1]
    f[x][j+k][0][1]+=f[y][k][1][1]*g[j][0][0]
    f[x][j+k][1][0]+=f[y][k][0][0]*g[j][1][0]
    f[x][j+k][1][0]+=f[y][k][0][1]*g[j][1][0]
    f[x][j+k][1][1]+=f[y][k][1][0]*g[j][1][0]
    f[x][j+k][1][1]+=f[y][k][1][1]*g[j][1][0]
    f[x][j+k][1][1]+=f[y][k][0][0]*g[j][1][1]
    f[x][j+k][1][1]+=f[y][k][0][1]*g[j][1][1]
    f[x][j+k][1][1]+=f[y][k][1][0]*g[j][1][1]
    f[x][j+k][1][1]+=f[y][k][1][1]*g[j][1][1]
    

    需要卡常数和内存。

    源代码:

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    typedef long long int64;
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    const int N=1e5+1,M=101,mod=1e9+7;
    int m,size[N],f[N][M][2][2],g[M][2][2],h[N];
    struct Edge {
    	int to,next;
    };
    Edge e[N<<1];
    inline void add_edge(const int &u,const int &v) {
    	e[++h[0]]=(Edge){v,h[u]};h[u]=h[0];
    	e[++h[0]]=(Edge){u,h[v]};h[v]=h[0];
    }
    void dfs(const int &x,const int &par) {
    	f[x][0][0][0]=f[x][1][1][0]=size[x]=1;
    	for(unsigned i=h[x];i;i=e[i].next) {
    		const int &y=e[i].to;
    		if(y==par) continue;
    		dfs(y,x);
    		for(register int j=std::min(size[x],m);~j;j--) {
    			g[j][0][0]=f[x][j][0][0];
    			g[j][0][1]=f[x][j][0][1];
    			g[j][1][0]=f[x][j][1][0];
    			g[j][1][1]=f[x][j][1][1];
    			f[x][j][0][0]=f[x][j][0][1]=f[x][j][1][0]=f[x][j][1][1]=0;
    		}
    		for(register int j=std::min(size[x],m);~j;j--) {
    			for(register int k=std::min(size[y],m-j);~k;k--) {
    				(f[x][j+k][0][0]+=(int64)f[y][k][0][1]*g[j][0][0]%mod)%=mod;
    				(f[x][j+k][0][1]+=((int64)f[y][k][1][1]*(g[j][0][1]+g[j][0][0])+(int64)f[y][k][0][1]*g[j][0][1])%mod)%=mod;
    				(f[x][j+k][1][0]+=(int64)(f[y][k][0][0]+f[y][k][0][1])*g[j][1][0]%mod)%=mod;
    				(f[x][j+k][1][1]+=((int64)(f[y][k][1][0]+f[y][k][1][1])*g[j][1][0]+((int64)f[y][k][0][0]+f[y][k][0][1]+f[y][k][1][0]+f[y][k][1][1])%mod*g[j][1][1])%mod)%=mod;
    			}
    		}
    		size[x]+=size[y];
    	}
    }
    int main() {
    	const int n=getint();m=getint();
    	for(register int i=1;i<n;i++) {
    		add_edge(getint(),getint());
    	}
    	dfs(1,0);
    	printf("%d
    ",(f[1][m][0][1]+f[1][m][1][1])%mod);
    	return 0;
    }
    
  • 相关阅读:
    JavaScript DOMContentLoaded 和 load事件的区别
    Redux源码分析之combineReducers
    Redux源码分析之createStore
    LeetCode003 无重复字符的最长子串
    Navicat Premium 15 永久破解和2021版本最新IDEA破解(亲测有效)
    在Win10中安装虚拟机:VMware Workstation Player+Ubuntu20.04
    C# 对象复制三种方法效率对比——反射、序列化、表达式树
    nginx在个人网站上的优化(一)
    VUE3.0的打包配置修改
    Jenkins构建项目连接Repository URL的填坑之路
  • 原文地址:https://www.cnblogs.com/skylee03/p/9169146.html
Copyright © 2020-2023  润新知