zoukankan      html  css  js  c++  java
  • [国家集训队] Crash 的文明世界

    [国家集训队] Crash 的文明世界

    题目大意:如同([POI2008] STA-Station),不过求每个点(sumlimits_{j = 1}^{n}dis(i,j)^k)

    Solution

    太诡了

    [x^n = sumlimits_{i=1}^{n}egin{Bmatrix}n \i end{Bmatrix}cdot A_x^i ]

    考虑一个组合意义证明,就是给(n)个格子染(x)种色的方案数,等于先把这(n)个格子分成若干集合,在(x)个颜色中选出相同个数的颜色,每个集合染一种颜色(排列)的方案数。

    然后将排列数转化为可以应用帕斯卡定理的组合数

    [x^n = sumlimits_{i=1}^{n}egin{Bmatrix}n \i end{Bmatrix}cdot i!cdotinom{x}{i} ]

    然后我们就将题目给出的式子转化

    [sumlimits_{j=1}^{n}dis(i,j)^k=sumlimits_{j=1}^{n} sum_{m=1}^{k}egin{Bmatrix}k \m end{Bmatrix}cdot m!cdotinom{dis(i,j)}{m}=sumlimits_{m=1}^{k}egin{Bmatrix}k \m end{Bmatrix}cdot m!sumlimits_{j=1}^{n}inom{dis(i,j)}{m} ]

    第二类斯特林数的递推公式

    将p个物体划分成k个非空的不可辨别的集合的方法数。

    [egin{Bmatrix}n \x end{Bmatrix} =egin{Bmatrix}n-1 \x end{Bmatrix} cdot x + egin{Bmatrix}n-1 \x-1 end{Bmatrix} ]

    树形DP

    (d[x,i])表示当上面的(k=i)(x)的子树对(x)的贡献,(u[x,i])表示除了(x)子树外的节点对(x)的贡献。

    1. (d[x][j] = (d[x][j] + d[e[i].to][j - 1] + d[e[i].to][j]))

    2. (u[x][m] = (u[x][m] + u[fa][m] + u[fa][m-1]))
      (u[x][m] = (u[x][m] + d[fa][m] + d[fa][m-1]))
      $ u[x][m] = (u[x][m] - d[x][m] - d[x][m - 1]) ( )u[x][m] = (u[x][m] - d[x][m - 1]-d[x][m - 2])$

    (u)加上父亲结点的所有,减去的分别是(x)的子树对(u[fa,m])(up[fa,m-1])的贡献。

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 5e4 + 10;
    const int M = N << 1;
    const int Mod = 10007;
    
    int n, K, ecnt;
    int head[N], fac[N];
    int s2[N][200], d[N][200], u[N][200], ans[N];
    
    struct Edge{
    	int to, next;
    }e[M];
    
    inline void adde(int x, int y) {
    	e[++ecnt].to = y;
    	e[ecnt].next = head[x];
    	head[x] = ecnt;
    }
    
    inline int read() {
    	int w = 0, f = 1;
    	char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9') {
    		w = (w << 3) + (w << 1) + (c ^ 48);
    		c = getchar();
    	}
    	return w * f;
    }
    
    void dfs1(int x, int fa) {
    	d[x][0] = 1;//实质上是size
    	for(int i = head[x]; i; i = e[i].next) {
    		if(e[i].to != fa) {
    			dfs1(e[i].to, x);
    			d[x][0] = (d[x][0] + d[e[i].to][0]) % Mod;//加上子节点的size 
    			for(int j = 1; j <= K; ++j) {
    				d[x][j] = (d[x][j] + d[e[i].to][j - 1] + d[e[i].to][j]) % Mod;//更新子树内的 
    			}			
    		}
    	} 
    }
    
    void dfs2(int x, int fa) {		
    	u[x][0] = n - d[x][0];//所有节点减去子树内的 
    	if(fa) {
            for (int m = 1; m <= K; ++m) {
                u[x][m] = (u[x][m] + u[fa][m] + u[fa][m-1]) % Mod; 
                u[x][m] = (u[x][m] + d[fa][m] + d[fa][m-1]) % Mod;
                u[x][m] = (u[x][m] - d[x][m] - d[x][m - 1]) % Mod;
                u[x][m] = (u[x][m] - d[x][m - 1]) % Mod;
                if(m > 1) u[x][m] = (u[x][m] - d[x][m - 2]) % Mod;
                u[x][m] = (u[x][m] + Mod) % Mod;
            }
    	} 
    	for(int i = head[x]; i; i = e[i].next)
    		if(e[i].to != fa) dfs2(e[i].to, x);
    	return;
    }
    
    int main() {
    	cin >> n >> K;
    	for(int i = 1, la, lb; i <= n - 1; ++i) {
    		la = read(), lb = read();
    		adde(la, lb);
    		adde(lb, la);
    	}
    	s2[1][1] = 1;
    	for(int i = 2; i <= K; ++i)
    		for(int j = 1; j <= K; ++j) {
    						s2[i][j] = ((s2[i - 1][j] * j) % Mod + s2[i - 1][j - 1]) % Mod;
    		}
    	fac[1] = 1;
    	for(int i = 2; i <= K; ++i){
    		fac[i] = (fac[i - 1] * i) % Mod;		
    	}
    
    	dfs1(1, 0);
    	dfs2(1, 0);
    	for(int i = 1; i <= n; ++i) {
    		for(int j = 1; j <= K; ++j) {
    			ans[i] = (ans[i] + (s2[K][j] % Mod * fac[j] % Mod) % Mod * (d[i][j] + u[i][j]) % Mod) % Mod;
    		}
    		printf("%d
    ", ans[i] % Mod);
    	}
    
    		
    	return 0;
    }
    
  • 相关阅读:
    每周进度条07
    软件需求模式阅读笔记06
    每周进度条06
    软件需求模式阅读笔记05
    Django之ModelForm组件
    Django的性能优化
    分页,缓存,序列化,信号
    Django补充——中间件、请求的生命周期等
    Git基础介绍和使用
    Django基础之三
  • 原文地址:https://www.cnblogs.com/LMSH7/p/9680863.html
Copyright © 2011-2022 走看看