树形DP+前缀和优化 nkoj P3723

评测说明 : 时限1000ms
问题描述

【问题描述】

    宝批龙,又叫宝气。虽然恐龙已经灭绝数千万年,但是宝批龙却仍然顽强的活在这个世界上,而且经常发宝。

    从前有座山,山上有很多个黑曲麻恐的防空洞,每个黑曲麻恐的防空洞里都有若干个宝批龙,宝批龙都发同样的宝。

从前有座山,这座山只有一个山顶。山上有很多条上山的路,每条路的终点都是山顶。

山上有很多个黑曲麻恐的防空洞,其中山顶有一个黑曲麻恐的防空洞。除了山顶的黑曲麻恐的防空洞,山上的其他每一个黑曲麻恐的防空洞都可以向山顶的方向走,而且这个方向是唯一的。从一个黑曲麻恐的防空洞向着上山方向走一段距离之后,可以到达另外一个黑曲麻恐的防空洞,到达的这个黑曲麻恐的防空洞称为下面那个黑曲麻恐的防空洞的上洞。

每个黑曲麻恐的防空洞里都有若干个宝批龙,每个黑曲麻恐的防空洞的容纳量是有限的,一个黑曲麻恐的防空洞里住的宝批龙数量不能太多,否则会非常拥挤。

宝批龙都发同样的宝,他们认为每个黑曲麻恐的防空洞的上洞里住的宝批龙数量不能超过这个黑曲麻恐的防空洞里住的宝批龙数量,除非上洞恰好住满。如果违背了这个规则,就是发宝失败,他们不再是宝批龙,宝批龙就从此灭绝。

现在你知道了每个黑曲麻恐的防空洞的容纳量,你想计算山上的宝批龙有多少种分布情况。

输入格式

第一行一个整数,表示黑曲麻恐的防空洞的数量。每个黑曲麻恐的防空洞按编号,其中编号为1的黑曲麻恐的防空洞在山顶。

第二行个整数,第i个数,表示第i个黑曲麻恐的防空洞的容纳量,即这个黑曲麻恐的防空洞里住的宝批龙数量必须在范围之内。

第三行个整数,第i个数是,表示第i+1个黑曲麻恐的防空洞的上洞的编号。

输出格式

一行一个整数,表示山上宝批龙分布情况数量mod 1234567891(这是 个素数)的结果。 

样例输入 1


2 3 3 
1 1

样例输出 1

41

样例输入 2


3 1 3 
1 1 

 
f[i][j]表示 以i 为根的 i住j个的方案数 前缀和优化即可
nodgd出的题真的是毒瘤 
方程很好推 就是卡空间
卡我记忆化搜索
学到了top序列求DP (应该叫做DAG+DP)
code:
//
#include<stdio.h>
#include<bits/stdc++.h>
#define mod 1234567891
#define ll long long 
using namespace std;
#define maxnn 500001
unsigned int n;
unsigned int c[maxnn];
unsigned int sum[maxnn][101];
unsigned int  las[maxnn],nex[maxnn],tot,en[maxnn];
unsigned int topp[maxnn],tot1;
void add(unsigned int a,unsigned int b)
{
    en[++tot]=b;
    nex[tot]=las[a];
    las[a]=tot;
}
void dfs(int p)
{
    for(int i=las[p];i;i=nex[i]) dfs(en[i]);
    topp[++tot1]=p;
} 

int main()
{
    cin>>n;
    unsigned int x;
    for(unsigned int i=1;i<=n;i++)
        scanf("%d",&c[i]);
    for(unsigned int i=1;i<n;i++)
    {
        scanf("%d",&x);
        add(x,i+1);
    }
    dfs(1);
    for(int z=1;z<=n;z++)
    {
        int v=topp[z];
    for(unsigned int cii=0;cii<=c[v];cii++)
    {
        unsigned int ans=1;
        if(cii==c[v])
        {
            for(unsigned int i=las[v];i;i=nex[i])
            {
                unsigned int y=en[i];
                ans=(((ll)ans%mod)*(sum[y][c[y]]%mod))%mod;
            }
        }
        else
        {
            unsigned int now;
            for(int i=las[v];i;i=nex[i])
            {
                now=0;    
                unsigned int y=en[i];
                if(cii>0&&c[y]>=cii)
                now=(sum[y][c[y]]%mod-sum[y][cii-1]%mod+mod)%mod;
                else
                if(c[y]>=cii)
                now=sum[y][c[y]]%mod;
                else
                {
                    ans=0;break;
                }
            ans=(((ll)ans%mod)*(now%mod))%mod;
            }
        }
        if(cii>=1)
            sum[v][cii]=(sum[v][cii-1]%mod+ans%mod)%mod;
        else
        {
            sum[v][cii]=ans%mod;
        }
    }
    }
    printf("%d\n",sum[1][c[1]]%mod);
}

猜你喜欢

转载自www.cnblogs.com/OIEREDSION/p/11314185.html
今日推荐