zoukankan      html  css  js  c++  java
  • CF1097G Vladislav and a Great Legend

    传送门


    题目大意

    一棵$n$个点的树,一个点集$S$的权值定义为把这个点击连成一个联通块的最少边数,求:

    $$ans=sum_{Sin U}f(S)^k$$


    题解

    这题跟gdoi那道题差不多

    先把柿子化一下变成

    $$ans=sum_{i=0}^k egin{Bmatrix}k\iend{Bmatrix} i! sum_{Sin U}egin{pmatrix}f(S)\iend{pmatrix}$$

    然后我们就相当于去统计大小为$i$的边集的贡献

    这个可以通过dp来实现

    定义$f_{x,i}$表示$x$子树内所有点与父亲的连边中选出了$i$条边,子树内选择的点的方案数

    dp过程就是首先算出不包括$x$和父亲的边的方案数,然后再加上这条边就可以了

    在$x$和父亲的边加入边集时,要注意$x$的子树内外会不会一个点都没选

    减去这些方案就可以了


    Code

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #define LL long long
    using namespace std;
    const LL Maxn = 100010;
    const LL Maxk = 210;
    const LL Mod = 1e9+7;
    LL f[Maxn][Maxk], g[Maxk];
    LL h[Maxk];
    LL n, K;
    struct node {
    	LL y, next;
    }a[Maxn<<1]; LL first[Maxn], len;
    void ins(LL x, LL y) {
    	len++;
    	a[len].y = y;
    	a[len].next = first[x]; first[x] = len;
    }
    LL Stir2[Maxk][Maxk], jc[Maxk];
    LL siz[Maxn];
    void up(LL &x, LL y) { x = (x + y) % Mod; }
    void dfs(LL x, LL fa) {
    	f[x][0] = 2;
    	siz[x] = 1;
    	for(LL k = first[x]; k; k = a[k].next){
    		LL y = a[k].y;
    		if(y == fa) continue;
    		dfs(y, x);
    		for(LL i = 0; i < siz[x]+siz[y] && i <= K; i++) g[i] = 0;
    		for(LL i = 0; i < siz[x] && i <= K; i++){
    			for(LL j = 0; j <= siz[y] && j <= K-i; j++) up(g[i+j], f[x][i]*f[y][j]);
    		}
    		siz[x] += siz[y];
    		for(LL i = 0; i < siz[x] && i <= K; i++) f[x][i] = g[i];
    	}
    	if(x != 1){
    		for(LL i = 0; i < K; i++){
    			up(h[i+1], Mod-f[x][i]);
    			if(i == 0) up(h[1], 1);
    		}
    	} else for(LL i = 1; i <= K; i++) up(h[i], f[x][i]);
    	for(LL i = K; i > 0; i--) up(f[x][i], f[x][i-1]);
    	up(f[x][1], Mod-1);
    }
    int main() {
    	LL i, j, k;
    	scanf("%lld%lld", &n, &K);
    	Stir2[0][0] = 1;
    	for(i = 1; i <= K; i++){
    		for(j = 1; j <= i; j++) Stir2[i][j] = (j*Stir2[i-1][j]+Stir2[i-1][j-1])%Mod;
    	}
    	jc[0] = 1;
    	for(i = 1; i <= K; i++) jc[i] = jc[i-1]*i%Mod;
    	for(i = 1; i < n; i++){
    		LL x, y;
    		scanf("%lld%lld", &x, &y);
    		ins(x, y); ins(y, x);
    	}
    	dfs(1, 0);
    	LL ans = 0;
    	for(i = 1; i <= K; i++) up(ans, Stir2[K][i]*jc[i]%Mod*h[i]);
    	printf("%lld
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    关于vue的一些总结
    mvc中html导出成word下载-简单粗暴方式
    获取ip地址及城市信息
    .net中html转pdf
    div+css布局的问题
    js面向对象总结
    ES5&&ES6
    前端问题总结
    在vue的项目中引入swiper插件
    vue脚手架的使用
  • 原文地址:https://www.cnblogs.com/darklove/p/10232333.html
Copyright © 2011-2022 走看看