CF901 A. Hashing Trees(构造)

A. Hashing Trees
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Sasha is taking part in a programming competition. In one of the problems she should check if some rooted trees are isomorphic or not. She has never seen this problem before, but, being an experienced participant, she guessed that she should match trees to some sequences and then compare these sequences instead of trees. Sasha wants to match each tree with a sequence a0, a1, …, ah, where h is the height of the tree, and ai equals to the number of vertices that are at distance of i edges from root.

Unfortunately, this time Sasha’s intuition was wrong, and there could be several trees matching the same sequence. To show it, you need to write a program that, given the sequence ai, builds two non-isomorphic rooted trees that match that sequence, or determines that there is only one such tree.

Two rooted trees are isomorphic, if you can reenumerate the vertices of the first one in such a way, that the index of the root becomes equal the index of the root of the second tree, and these two trees become equal.

The height of a rooted tree is the maximum number of edges on a path from the root to any other vertex.

Input
The first line contains a single integer h (2 ≤ h ≤ 105) — the height of the tree.

The second line contains h + 1 integers — the sequence a0, a1, …, ah (1 ≤ ai ≤ 2·105). The sum of all ai does not exceed 2·105. It is guaranteed that there is at least one tree matching this sequence.

Output
If there is only one tree matching this sequence, print “perfect”.

Otherwise print “ambiguous” in the first line. In the second and in the third line print descriptions of two trees in the following format: in one line print integers, the k-th of them should be the parent of vertex k or be equal to zero, if the k-th vertex is the root.

These treese should be non-isomorphic and should match the given sequence.

Examples
inputCopy
2
1 1 1
outputCopy
perfect
inputCopy
2
1 2 2
outputCopy
ambiguous
0 1 1 3 3
0 1 1 3 2
Note
The only tree in the first example and the two printed trees from the second example are shown on the picture:

题意:给你一个数组a,ai代表树的第i深度的节点数,现在问你存不存在每层节点数相同,但是不同构的树,如果存在输出ambiguous,接下来输出两颗树,否则输出perfect

思路:同构就是两棵树,如果每层节点的度数一样,那么它就是同构的,所以可以得出结论,如果连续两层节点数大于1的话,那么就存在两颗不同构的树
同构可以看下面这篇文章
树的同构

代码:

#include<bits/stdc++.h>
#define LL long long
#define Max 100005
const LL mod=1e9+7;
const LL LL_MAX=9223372036854775807;
using namespace std;
int a[Max],n;
int b[2*Max],c[2*Max];
int main()
{
    scanf("%d",&n);
    int flag=0,index;
    for(int i=1;i<=n+1;i++){
        scanf("%d",&a[i]);
        if(a[i]>1 && a[i-1]>1){
            flag=1;
            index=i;
        }
    }
    if(!flag){
        printf("perfect\n");
    }
    else{
        printf("ambiguous\n");
        int t=0,len=0;
        for(int i=1;i<=n+1;i++){
            for(int j=0;j<a[i];j++){
                b[len]=t;
                c[len++]=t;
                if(i==index && j==a[i]-1){
                    c[len-1]=b[len-1]-1;
                }
            }
            t+=a[i];
        }
        for(int i=0;i<len;i++)
            printf("%d ",b[i]);
        printf("\n");
        for(int i=0;i<len;i++)
            printf("%d ",c[i]);
        printf("\n");
    }
    return 0;
}

### 替代方案或实现方式 `sun.misc.Hashing.randomHashSeed` 是一个内部类方法,主要用于生成随机的哈希种子值。然而,该方法在 JDK 8 中被移除,因为其多线程性能问题导致了潜在的性能瓶颈。以下是几种替代方案和实现方式: #### 1. 使用 `ThreadLocalRandom` `ThreadLocalRandom` 是 Java 提供的一个高性能随机数生成器,专为多线程环境设计。它可以作为 `randomHashSeed` 的替代方案,用于生成随机种子值。 ```java int randomHashSeed = ThreadLocalRandom.current().nextInt(); ``` 这种方法避免了多线程环境下的竞争问题,同时提供了高效的随机数生成能力[^6]。 #### 2. 自定义哈希种子生成逻辑 可以通过简单的数学运算生成一个伪随机的哈希种子值。例如,结合当前时间戳和线程 ID 来生成一个唯一的种子值: ```java int randomHashSeed = (int) (System.currentTimeMillis() ^ Thread.currentThread().getId()); ``` 这种方法虽然简单,但在某些场景下可能不够随机,因此需要根据具体需求进行调整[^7]。 #### 3. 使用 `SecureRandom` 如果对随机性要求较高,可以使用 `SecureRandom` 类生成更安全的随机数。尽管它的性能略低于 `ThreadLocalRandom`,但在安全性至关重要的场景中是一个不错的选择。 ```java SecureRandom secureRandom = new SecureRandom(); int randomHashSeed = secureRandom.nextInt(); ``` 这种方法适用于需要防止攻击者预测哈希种子值的场景[^8]。 #### 4. 模仿原始实现 如果必须模仿 `sun.misc.Hashing.randomHashSeed` 的行为,可以通过以下方式实现: ```java private static final AtomicInteger hashSeed = new AtomicInteger(0); public static int randomHashSeed() { return hashSeed.incrementAndGet(); } ``` 这种方式通过 `AtomicInteger` 确保了线程安全性,同时实现了类似的功能。需要注意的是,这种方法生成的种子值并非完全随机,而是递增的整数序列[^9]。 ### 注意事项 - 如果选择自定义实现,需确保生成的种子值分布均匀,以减少哈希碰撞的概率。 - 在高并发环境下,优先选择 `ThreadLocalRandom` 或 `SecureRandom`,以避免性能瓶颈。 - 如果仅需要一个简单的随机数生成器,可以使用 `Math.random()` 并将其转换为整数形式。 ```java int randomHashSeed = (int) (Math.random() * Integer.MAX_VALUE); ``` 这种方法简单易用,但随机性较差,不推荐在高并发或安全性要求较高的场景中使用[^10]。 ### 示例代码 以下是一个综合实现的示例,展示了如何在不同场景下选择合适的替代方案: ```java public class HashSeedGenerator { public static int generateThreadLocalRandomSeed() { return ThreadLocalRandom.current().nextInt(); } public static int generateSecureRandomSeed() { SecureRandom secureRandom = new SecureRandom(); return secureRandom.nextInt(); } public static int generateCustomSeed() { return (int) (System.currentTimeMillis() ^ Thread.currentThread().getId()); } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值