当前位置: 首页 > news >正文

缪尔赛思又来到了你的面前(哈希)

定义一棵根节点为 1 1 1 n ( 2 ≤ n ≤ 1 0 3 ) n(2≤n≤10^3) n(2n103) 个节点的树的哈希值为:
H = ∑ i = 1 n X i Y f a ( i ) m o d 998244353 H=∑^n_{i=1}X^iY^{fa(i)}\ mod\ 998244353 H=i=1nXiYfa(i) mod 998244353
f a ( i ) fa(i) fa(i) 表示 i i i 的父亲节点, 1 1 1 为根节点, f a ( 1 ) = 1 fa(1)=1 fa(1)=1

$X,Y(1≤X,Y<998244353) $为给定的两个随机值。

请构造两棵大小为 n n n 的树,他们有相同的哈希值,但两棵树要求不一样。

我们认为两棵大小为 n n n 的树不一样:

  • 记数组 f a ( i ) fa(i) fa(i) 表示第 i i i 个节点的父亲,其中 f a ( 1 ) = 1 fa(1)=1 fa(1)=1
  • 节点 1 1 1 2 2 2 3 … … n 3……n 3……n 对应的 f a ( 1 ) , f a ( 2 ) , f a ( 3 ) , … , f a ( n ) fa(1),fa(2),fa(3),…,fa(n) fa(1),fa(2),fa(3),,fa(n)排成一排,得到了我们所要的 f a fa fa数组。
  • 对于两棵树 u , v u,v u,v,其数组 f a u , f a v fa_u,fa_v fau,fav,存在一个 j j j,使得 f a u ( j ) ≠ f a v ( j ) fa_u(j)≠fa_v(j) fau(j)=fav(j),此时认为两棵树不一样。

你需要输出两棵树的 f a fa fa 数组。

你需要保证输出的 fa 数组可以构成一棵树。

保证输入数据必然有解。

输入格式

一行三个数 n , X , Y n,X,Y n,X,Y

输出格式

输出共两行。

每行 n n n个数,分别表示两棵树的 f a fa fa 数组。

若有多组解,请输出任意一组满足题意的解即可。

样例

input
8 1 1
output
1 1 1 6 1 1 1 1
1 1 1 1 1 1 1 1

这里先说明一个有趣的事实,然后再说明解题思路

我们知道最多有365个人的生日是不同的,但是随着生日不同的人数增多,概率下降的很快:当要找出23个人的生日不同时,概率就下降到了0.5;当要找出100个人的生日不同时,概率就下降到了 1 0 − 7 10^{-7} 107

所以哈希冲突的概率随着数量的增多上升的很快,本题就是利用这个性质

我们利用并查集+随机数进行树的构造,每次都能得到一个哈希值

当得到的哈希值出现重复时,我们就可以输出这两棵树的fa数组了

但是仅仅这样会TLE,需要优化

观察到只有20个节点的树就可以有很多种不同的结构,所以我们只对前20个节点进行随机排列,之后的所有节点全部连接到根节点上

AC代码如下

#include <iostream>
#include <time.h>
#include <stdlib.h>
#include <random>
#include <map>
#define int unsigned long long
using namespace std;
const int max_n = 1e3;
const int max_try = 100050;
const int limit = 20;
const int p = 998244353;int n, x, y;
int fa2[max_try][limit + 1], tmpfa[limit + 1];
map<int, int>ans;int quick_pow(int x, int y) {int ret = 1;while (y) {if (y % 2) ret = (ret * x) % p;x = (x * x) % p;y /= 2;}return ret % p;
}void init(int n) {for (int i = 1; i <= n; i++) {tmpfa[i] = i;}
}int find(int x) {return x == tmpfa[x] ? x : (tmpfa[x] = find(tmpfa[x]));
}bool insame(int x, int y) {return find(x) == find(y);
}void merge(int x, int y) {x = find(x);y = find(y);tmpfa[x] = y;
}bool check(int id, int check, int tmpn, int tmphash) {init(tmpn);for (int i = 2; i <= tmpn; i++) {if (insame(i, fa2[id][i])) return false;else merge(i, fa2[id][i]);}for (int i = 2; i <= tmpn; i++) {if (!insame(1, i)) {return false;}}int hashcheck = tmphash;for (int i = 1; i <= n; i++) {hashcheck = ((hashcheck + (quick_pow(x, i) + quick_pow(y, fa2[id][i])) % p) % p) % p;}return check == hashcheck;
}signed main() {cin >> n >> x >> y;srand((unsigned)time(NULL));int cnt = 0;int tmpn = min(n, limit);int tmphash = 0;for (int i = tmpn + 1; i <= n; i++) {tmphash = (tmphash + (quick_pow(x, i) * quick_pow(y, 1)) % p) % p;}while (1) {int hash2 = (tmphash + (x * y) % p) % p;fa2[cnt][1] = 1;init(tmpn);int flag = 0;for (int i = 2; i <= tmpn; i++) {int rand_num = rand() % tmpn + 1;while (insame(i, rand_num)) rand_num = rand() % tmpn + 1;merge(i, rand_num);fa2[cnt][i] = rand_num;hash2 = (hash2 + (quick_pow(x, i) * quick_pow(y, fa2[cnt][i])) % p) % p;}if (ans.count(hash2)) {int tmpid = ans[hash2];for (int i = 1; i <= n; i++) {if (fa2[tmpid][i] != fa2[cnt][i]) {flag = 1;break;}}if (flag) {//if (check(tmpid, hash2, tmpn, tmphash) || //	check(cnt, hash2, tmpn, tmphash)) {//	printf("ERROR!");//	return -1;//}for (int i = 1; i <= n; i++) {if (i <= tmpn) printf("%lld", fa2[tmpid][i]);else printf("1");if (i != n) printf(" ");}printf("\n");for (int i = 1; i <= n; i++) {if (i <= tmpn) printf("%lld", fa2[cnt][i]);else printf("1");if (i != n) printf(" ");}return 0;}}else {ans[hash2] = cnt++;}}return 0;
}

相关文章:

  • windows、mac、linux中node版本的切换(nvm管理工具),解决项目兼容问题 node版本管理、国内npm源镜像切换
  • python:pycharm虚拟解释器报错环境位置目录为空
  • 人生苦短,我学python之数据类型(下)
  • “高考钉子户”唐尚珺决定再战2024年高考
  • Proteus仿真小技巧(隔空连线)
  • C语言:有两个磁盘文件A和B,各存放一行字母,要求把这两个文件中的信息合并(按字母顺序排列),输出到一个新文件C中
  • 揭秘Python的魔法:装饰器的超能力大揭秘 ‍♂️✨
  • AI视频智能分析技术赋能营业厅:智慧化管理与效率新突破
  • 【SpringCloud】Spring Cloud基本介绍
  • python爬虫-爬小说
  • PTT票据传递攻击
  • 基于单片机电梯控制系统设计与实现
  • Vitis HLS 学习笔记--抽象并行编程模型-控制驱动与数据驱动
  • VBA读取文本文件数据
  • Docker(一) Docker概述
  • [js高手之路]搞清楚面向对象,必须要理解对象在创建过程中的内存表示
  • Go 语言编译器的 //go: 详解
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • Javascript弹出层-初探
  • JS正则表达式精简教程(JavaScript RegExp 对象)
  • k8s 面向应用开发者的基础命令
  • python3 使用 asyncio 代替线程
  • Vue学习第二天
  • 闭包--闭包之tab栏切换(四)
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 从重复到重用
  • 使用Gradle第一次构建Java程序
  • 它承受着该等级不该有的简单, leetcode 564 寻找最近的回文数
  • 通过npm或yarn自动生成vue组件
  • 通过调用文摘列表API获取文摘
  • 支付宝花15年解决的这个问题,顶得上做出十个支付宝 ...
  • # Maven错误Error executing Maven
  • ###51单片机学习(1)-----单片机烧录软件的使用,以及如何建立一个工程项目
  • #我与Java虚拟机的故事#连载05:Java虚拟机的修炼之道
  • (02)vite环境变量配置
  • (10)ATF MMU转换表
  • (16)Reactor的测试——响应式Spring的道法术器
  • (9)目标检测_SSD的原理
  • (day 12)JavaScript学习笔记(数组3)
  • (NO.00004)iOS实现打砖块游戏(十二):伸缩自如,我是如意金箍棒(上)!
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (二)换源+apt-get基础配置+搜狗拼音
  • (黑马C++)L06 重载与继承
  • (汇总)os模块以及shutil模块对文件的操作
  • (机器学习的矩阵)(向量、矩阵与多元线性回归)
  • (论文阅读22/100)Learning a Deep Compact Image Representation for Visual Tracking
  • (七)MySQL是如何将LRU链表的使用性能优化到极致的?
  • (十六)串口UART
  • (转)C语言家族扩展收藏 (转)C语言家族扩展
  • (转)大型网站的系统架构
  • (转载)OpenStack Hacker养成指南
  • ****Linux下Mysql的安装和配置
  • .dat文件写入byte类型数组_用Python从Abaqus导出txt、dat数据
  • .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现