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;
    } 
  • 相关阅读:
    java实现第七届蓝桥杯凑算式
    java实现第七届蓝桥杯凑算式
    java实现第七届蓝桥杯凑算式
    java实现第七届蓝桥杯分小组
    java实现第七届蓝桥杯分小组
    java实现第七届蓝桥杯分小组
    java实现第七届蓝桥杯分小组
    java实现第七届蓝桥杯分小组
    java实现第七届蓝桥杯骰子游戏
    “枚举类型”与“枚举变量”有什么区别?
  • 原文地址:https://www.cnblogs.com/shenben/p/10424160.html
Copyright © 2011-2022 走看看