zoukankan      html  css  js  c++  java
  • [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;
    }
    
  • 相关阅读:
    Android ActivityGroup的使用代码将子activty 的layout加入到主activity中
    ERROR: Application requires API version 10. Device API version is 8
    简单实现Android实现九宫格
    继承中new 与 override的作用
    Sql server 数量累计求和
    Android 应用程序窗体显示状态操作(requestWindowFeature()的应用)
    UDP传输错误 无法找到程序集“client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    堆与栈的区别
    Decorator模式
    时间为O(1)删除节点的代码
  • 原文地址:https://www.cnblogs.com/skylee03/p/9169146.html
Copyright © 2011-2022 走看看