宇宙树

Problem Description
在传承至今的典籍中认为,每个宇宙都是十种宇宙中的一种:炎之宇宙、光之宇宙、冰之宇宙、风之宇宙、雷之宇宙、土之宇宙、水之宇宙、木之宇宙、钢之宇宙、暗之宇宙,各表示了一个宇宙内部的主要元素。在最初始的大爆炸之后,在混沌中产生了最初的若干个宇宙,这些宇宙的类型是以上十种之一,可能相同,可能不同。从这些宇宙开始,每过一个纪元,各个宇宙都有可能孕育出多个新的宇宙(类型可能相同,可能不同)。可以预见,从任何一个初始宇宙开始,在经过若干个纪元之后,就有可能得到非常多新的宇宙。
这里写图片描述

在更高的维度上,一种名为“孵化者”的生物在观测着这些宇宙。“孵化者”们把宇宙之间的孕育关系表示成一棵树,称为“宇宙树”。下图便是一棵可能的宇宙树,其中用0~9来分别代表十种宇宙的类型,那么这棵宇宙树便是从一个类型为2的初始宇宙开始,孕育出了类型分别为6、1、2的三个宇宙,而类型为6的那个宇宙又孕育出了类型为0和9的两个宇宙,类型为2的那个非初始宇宙孕育出了类型为5的宇宙。

“孵化者”们发现,一个宇宙与它孕育出的新宇宙之间并不是完全没有联系的,旧宇宙的信息会被携带一部分到新的宇宙中。它们猜想,既然宇宙类型的生成是“随机”的,那么在很多很多个纪元之后,再孕育出的新宇宙,其宇宙内部很可能会是十种元素达到平衡的状态。“孵化者”们认为,可以观测就可以干涉,可以干涉就可以控制,那么研究当前这些宇宙的类型便十分重要。

“孵化者”们认为,每一个处于宇宙树叶结点的宇宙,都是其所在分支上的最新宇宙,可以把这些叶结点的宇宙称为“新宇宙”。根据它们的猜想,这些宇宙的类型虽然从主要元素上来说属于十种中的一种,但如果把它们划分得更细致的话,是可以得到更准确的类型信息的。“孵化者”们把一个宇宙的“准确类型”定义为:从单棵宇宙树的初始宇宙开始、沿着孕育关系向下到达该宇宙的过程中形成的路径上的各类型的拼接结果就是这个宇宙的“准确类型”。例如在上图中,主类型为0的宇宙的“准确类型”是260,主类型为9的的宇宙的“准确类型”是269,主类型为1的的宇宙的“准确类型”是21,主类型为5的宇宙的“准确类型”是225。

为了研究宇宙类型的混合结果,“孵化者”们把一棵宇宙树的所有“新宇宙”的“准确类型”求和,并将得到的结果称为这棵宇宙树的类型,这有助于它们进行下一步研究。例如对上面的图来说,这棵宇宙树的类型便是260+269+21+225=775。

现在“孵化者”们想知道,当前存在的所有宇宙树的类型分别是什么。

Input
每个输入文件中一组数据。
对每组数据,第一行为两个正整数N(1 <= N <= 10000, 0 <= M < N),分别表示宇宙的个数与孕育关系的条数。假设宇宙的编号为0~N-1,且每棵宇宙树的初始宇宙的编号一定是这棵宇宙树中最小的。
接下来一行N个整数,其中第i个整数表示编号为i-1的宇宙的主类型。
接下来M行,每行两个整数u和v(0 <= u < N, 0 <= v < N, u != v),表示编号为u的宇宙孕育了编号为v的宇宙。数据保证同一对(u,v)只会出现一次。

Output
第一行一个整数,表示宇宙树的个数K。
第二行K个整数,分别表示这K个宇宙树的类型。输出顺序为,如果一棵宇宙树的初始宇宙编号比其他宇宙树的小,那么就优先输出。
行末不允许有多余的空格。

Sample Input
10 8
2 6 1 2 0 9 5 0 3 6
0 1
0 2
0 3
1 4
1 5
3 6
7 8
8 9

Sample Output
2
775 36

Author
Shoutmon

Source
18浙大考研机试模拟赛

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
int n,m;
vector<int> v[10000+32],root;
vector<string> res;
int in[10000+32],val[10000+32];
void dfs(int r,string &rp)
{
    if(v[r].size()==0){
        res.push_back(rp);
        reverse(res.back().begin(),res.back().end());
        return;
    }
    for(int x:v[r])
    {
        rp.push_back(val[x]+'0');
        dfs(x,rp);
        rp.pop_back();
    }
}
string add(string a,string b)
{
    string rt;
    int sur=0,i=0,maxlen=max(a.size(),b.size());
    a+=string(maxlen-(int)a.size(),'0');
    b+=string(maxlen-(int)b.size(),'0');
    while(i<maxlen){
        int s=a[i]+b[i]-'0'-'0'+sur;
        rt+='0'+s%10;
        sur=s/10;
        ++i;
    }
    if(sur>0) rt+='0'+sur;
    return rt;
}
string getsum()
{
    string sum=res[0];
    int n=res.size();
    for(int i=1;i<n;++i)
        sum=add(sum,res[i]);
    while(sum.size()>1&&sum.back()=='0') sum.pop_back();
    reverse(sum.begin(),sum.end());
    return sum;
}
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=0;i<n;++i)
        scanf("%d",&val[i]);
    for(int i=0;i<m;++i){
        int x,y;
        scanf("%d %d",&x,&y);
        v[x].push_back(y);
        in[y]++;
    }
    for(int i=0;i<n;++i)
        if(in[i]==0) root.push_back(i);
    int len=root.size();
    printf("%d\n",len);
    for(int r:root){
        res.clear();
        string rp=string(1,val[r]+'0');
        dfs(r,rp);
        string sum=getsum();
        --len?printf("%s ",sum.c_str()):printf("%s\n",sum.c_str());
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值