uva1436 - Counting heaps 统计树的个数

We are given a rooted tree of n vertices. The vertices are to be labeled with numbers 1, 2,..., n so that each label is unique and the heap condition holds, i.e. the label of any vertex is less than the label of its parent. How many such labellings exist? Since this number may be quite large, calculate only its remainder modulo m.

Input 

The input contains several tree descriptions. The first line contains the number of input trees t (t$ \le$250). Each tree description begins with a line containing the size of the tree n (1$ \le$n$ \le$500000) and an integer m (2$ \le$m$ \le$109). n - 1 lines follow, i-th of which contains p(i + 1), the number of the parent of the i + 1-th vertex (1$ \le$p(i + 1)$ \le$i). Vertex number 1 will be the root in each tree, so its parent will not be given. Total size of the input will not exceed 50MB.

Output 

For each tree output the number of its valid labellings modulo given m.


Explanation for sample:The 8 possible labellings from the last example test case are as follows:

\epsfbox{p4390.eps}

Sample Input 

4 
3 1000000
1 
1 
4 1000000
1 
1 
1 
5 1000000
1 
2 
3 
4 
5 1000000
1 
1 
3 
3

Sample Output 

2 
6 
1 
8

  给了树的形状,节点编号1-N,父节点小于子节点,这样的树有多少个。

  跟训练指南上面那个村民排队(不能排在父亲前面)是一样的。根是i,假设每个子树有f(ci)中排法,每个子树有s(ci)个节点,先把每个子树中的元素看成一样的,就有(s(i)-1)!/(s(c1)*s(c2)...*s(ck)),再乘上每种子树的排法,也就是f(i)=f(c1)*f(c2)..*f(ck)*(s(i)-1)!/(s(c1)*s(c2)...*s(ck))。再把子树的f展开,注意到所有非根节点u以(s(u)-1)!在分子出现一次,以s(u)!在分母出现一次,最后化简完答案就是f(root)=(s(root)-1)!/(s(1)*s(2)..s(n)),因为s(root)=n+1,所以f(root)=n!/(s(1)*s(2)..s(n)),一般类似的问题都可以这么做。

  那么只需要统计出每个子树的节点个数就行了,递归应该会爆栈,用队列比较好。

  还有一个难点是取余,解决的办法是把分子分母都换成质数的幂的形式,在分子上幂是正的,分母上是负的,由于最后答案肯定是正整数,所以每个因子的系数肯定不会小于0的。快速幂就OK。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<cmath>
#define INF 0x3f3f3f3f
#define MAXN 500010
#define MAXM 50010
#define MAXNODE 4*MAXN
#define MOD 1000000000
#define eps 1e-9
using namespace std;
int T,P,N,M,isprime[MAXN],prime[MAXM],coef[MAXM],cnt[MAXN],isleaf[MAXN],fa[MAXN];
queue<int> q;
void prime_table(){
    P=0;
    isprime[1]=0;
    for(int i=2;i<MAXN;i++) isprime[i]=1;
    for(int i=2;i<MAXN;i++){
        if(isprime[i]){
            isprime[i]=P;
            prime[P++]=i;
        }
        for(int j=i+i;j<MAXN;j+=i) isprime[j]=0;
    }
}
void init(){
    memset(isleaf,0,sizeof(isleaf));
    memset(fa,-1,sizeof(fa));
    scanf("%d%d",&N,&M);
    for(int i=1;i<=N;i++) cnt[i]=1;
    for(int i=2;i<=N;i++){
        scanf("%d",&fa[i]);
        isleaf[fa[i]]++;
    }
    while(!q.empty()) q.pop();
    for(int i=1;i<=N;i++) if(!isleaf[i]) q.push(i);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        if(u==1) continue;
        cnt[fa[u]]+=cnt[u];
        isleaf[fa[u]]--;
        if(!isleaf[fa[u]]) q.push(fa[u]);
    }
}
long long bigpow(int x,int n,int M){
    long long ret=1,t=x%M;
    while(n){
        if(n&1) ret=ret*t%M;
        t=t*t%M;
        n>>=1;
    }
    return ret;
}
void fac(int x,int v){
    for(int i=0;prime[i]<=x;i++){
        if(x==1) return;
        while(x%prime[i]==0){
            coef[i]+=v;
            x/=prime[i];
        }
        //不加下面这个直接超时
        if(isprime[x]){
            coef[isprime[x]]+=v;
            return;
        }
    }
}
long long solve(){
    memset(coef,0,sizeof(coef));
    for(int i=2;i<N;i++) fac(i,1);
    for(int i=2;i<=N;i++) fac(cnt[i],-1);
    long long ret=1;
    for(int i=0;i<P;i++) if(coef[i]) ret=ret*bigpow(prime[i],coef[i],M)%M;
    return ret;
}
int main(){
    freopen("in.txt", "r", stdin);
    prime_table();
    scanf("%d",&T);
    while(T--){
        init();
        printf("%lld\n",solve());
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!对于复现VQA-Counting模型,您可以按照以下步骤进行操作: 1. 数据集准备:首先,您需要准备VQA-Counting数据集。该数据集通常包含图像、问题以及答案。您可以在VQA官方网站或者其他开源数据集库中找到该数据集。确保将数据集分成训练集、验证集和测试集。 2. 模型选择:选择适合的模型来解决VQA-Counting任务。常见的模型包括基于深度学习的视觉问答模型,如VGGNet、ResNet等。您可以选择现有的基于视觉问答的模型,并根据需要进行修改。 3. 模型训练:使用训练集中的图像、问题和答案,对所选模型进行训练。在训练过程中,您可以使用图像特征提取器来提取图像特征,并将其与问题特征进行融合。然后,根据融合后的特征预测答案中存在的对象数量。 4. 模型评估:使用验证集对训练好的模型进行评估。通过计算预测答案与真实答案之间的误差或准确性指标来评估模型的性能。您可以使用常见的评估指标,如准确率、均方根误差等。 5. 模型调优:根据评估结果,您可以调整模型的超参数或结构,以进一步提高模型的性能。可以尝试不同的优化算法、学习率、批次大小等参数来优化模型。 6. 模型测试:在测试集上进行模型测试,并计算模型的最终性能指标。确保在测试集上的性能与验证集上的性能相当,以验证模型的泛化能力。 请注意,以上提到的步骤仅为一般建议,具体实现会因您选择的模型和数据集而有所不同。此外,复现VQA-Counting模型可能需要较大的计算资源和时间,因此您需要进行必要的准备。 希望这些步骤对您有所帮助!如果您有任何进一步的问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值