zoukankan      html  css  js  c++  java
  • CF 954H Path Counting

    H. Path Counting
    time limit per test
    5 seconds
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    You are given a rooted tree. Let's denote d(x) as depth of node x: depth of the root is 1, depth of any other node x is d(y) + 1, where yis a parent of x.

    The tree has the following property: every node x with d(x) = i has exactly ai children. Maximum possible depth of a node is n, and an = 0.

    We define fk as the number of unordered pairs of vertices in the tree such that the number of edges on the simple path between them is equal to k.

    Calculate fk modulo 109 + 7 for every 1 ≤ k ≤ 2n - 2.

    Input

    The first line of input contains an integer n (2  ≤  n  ≤  5 000) — the maximum depth of a node.

    The second line of input contains n - 1 integers a1,  a2,  ...,  an - 1 (2 ≤  ai  ≤ 109), where ai is the number of children of every node xsuch that d(x) = i. Since an = 0, it is not given in the input.

    Output

    Print 2n - 2 numbers. The k-th of these numbers must be equal to fk modulo 109 + 7.

    Examples
    input
    Copy
    4
    2 2 2
    
    output
    Copy
    14 19 20 20 16 16 
    input
    Copy
    3
    2 3
    
    output
    Copy
    8 13 6 9 
    Note

    This the tree from the first sample:

     

    【题意】

    给出一棵深度为n的树,其中每个深度为i的节点都有a[i]个儿子。问对于每个k,有多少条简单路径满足其长度恰好为k

    n<=5000

     

    【分析】

    考虑枚举路径的端点。

    d[i,j]表示从某个深度为i的节点开始,只往下走且长度为j的路径条数。那么d[i,j]显然等于i的子树中深度为i+j的点数。

    u[i,j]表示从某个深度为i的节点开始,第一步必须往上走,且路径长度为j的方案。

    有两种转移,一种是走到父亲后继续往上,贡献就等于u[i-1,j-1]。另一种转移是走到父亲后就开始往下走,贡献就等于u[i,j-2]*(a[i-1]-1)

    综上,f[i][j]= f[i+1][j-1]*a[i]+

    f[i-1][j-1]+

    f[i][j-2]*(a[i-1]-1);

     

    【代码】

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define debug(x) cerr<<#x<<" "<<x<<'
    ';
    using namespace std;
    typedef long long ll;
    const int N=5005;
    const ll mod=1e9+7;
    const ll rev=5e8+4;
    int n,a[N],p[N],f[N][N<<1],ans[N<<1];
    int main(){
    	scanf("%d",&n);p[0]=1;
    	for(int i=1;i<n;i++) scanf("%d",&a[i]),p[i]=(ll)p[i-1]*a[i]%mod;
    	for(int i=n;i;i--){
    		f[i][0]=1;
    		for(int j=1;j<=n-i;j++){
    			f[i][j]=(ll)f[i+1][j-1]*a[i]%mod;
    			ans[j]=((ll)ans[j]+(ll)f[i][j]*p[i-1])%mod;
    		}
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=2*n-2;j>=1;j--){
    			f[i][j]=f[i-1][j-1];
    			if(i>1&&j>1&&j-2<n&&j<=i+n-2) f[i][j]=((ll)f[i][j]+(ll)f[i][j-2]*(a[i-1]-1))%mod;
    			ans[j]=((ll)ans[j]+(ll)f[i][j]*p[i-1])%mod;
    		}
    	}
    	for(int i=1;i<=2*n-2;i++) printf("%I64d ",(ll)ans[i]*rev%mod);
    	return 0;
    } 
  • 相关阅读:
    Cache Miss
    EmmyLua 注解标记总结
    关于浮点数计算时的精度问题 0.1+0.2不等于0.3
    Git-原理相关归纳-非入门
    读《非暴力沟通》
    Unity-图片压缩格式
    Git-大小写的坑
    将当前系统中的进程信息打印到文件中
    g++用法
    C++文本文件读写操作
  • 原文地址:https://www.cnblogs.com/shenben/p/10424160.html
Copyright © 2011-2022 走看看