信息学奥赛一本通 1463:门票

【题目链接】

ybt 1463:门票

【题目考点】

1. 哈希表

相关知识见:【模板:哈希表】信息学奥赛一本通 1456:【例题2】图书管理

【解题思路】

解法1:链地址法实现哈希表

数据范围限制为 65536 K B 65536KB 65536KB。

哈希表中最多可能保存 2 ∗ 10 6 2*10^6 2∗106个元素,平均每个元素占用内存 65536 ∗ 1024 / ( 2 ∗ 10 6 ) ≈ 33 B 65536*1024/(2*10^6)\approx 33B 65536∗1024/(2∗106)≈33B。

使用STL中的unordered_set类,内存开销比较大,当存储元素个数达到 2 ∗ 10 6 2*10^6 2∗106时,容易发生内存超限。

因此本题必须手动实现 哈希表。

开放地址法对内存空间需求较大,需要保证负载因子较小(一般为0.7)才可以降低哈希冲突的概率,因此表长会比存储的元素数量更大,有很多空间不能保存数据,对空间需求较高。

而链地址法的负载因子可以大于1,对内存空间需求相对较小,较为灵活。

参考【模板:哈希表】信息学奥赛一本通 1456:【例题2】图书管理中解法2可以以链地址法实现哈希表。

可以选择将哈希表写成类,或只是声明全局数组和函数来实现。

本题给定了初值 a 0 = 1 a_0=1 a0=1,以及递推公式 ( A ⋅ a i + a i   m o d   B )   m o d   C (A\cdot a_i+a_i\bmod B)\bmod C (A⋅ai+aimodB)modC,想要求出第一次出现重复项的编号。即当求出的值为 a i a_i ai时,如果 a i a_i ai在先前已经出现过,就输出 i i i。

如果答案超过 2 ∗ 10 6 2*10^6 2∗106,就输出-1。

我们可以根据 a a a序列的初始值和递推式,依次递推求出 a a a序列的每一项,设其中的一项为 d d d。注意 A ⋅ a i A\cdot a_i A⋅ai这一步要在long long类型下进行计算。

当求出 a i = d a_i=d ai=d时,首先在哈希表中查找是否存在 d d d,

  • 如果哈希表中存在 d d d,则输出 i i i,结束程序。
  • 如果哈希表中不存在 d d d,则将 d d d插入哈希表。

循环次数为 2 ∗ 10 6 2*10^6 2∗106,如果跳出了循环,则输出-1。

【题解代码】

解法1:链地址法实现哈希表

  • 写法1:写全局数组和函数实现哈希表,链表中结点地址为int类型
cpp 复制代码
#include <iostream>
#include <algorithm>
using namespace std;
#define N 2000003
struct Node
{
	int val;
	int next;	
} node[N];
int p, data[N];//data[i]:哈希值为i的单链表的第一个结点的地址
int Hash(int key)
{
	return key%N;
}
void insert(int key)
{
	int h = Hash(key), np = ++p;
	node[np].val = key;
	node[np].next = data[h];
	data[h] = np;
}
int count(int key)
{
	int h = Hash(key);
	for(int i = data[h]; i != 0; i = node[i].next)
		if(node[i].val == key)
			return 1;
	return 0;
}
int main()
{
	
	int a, b, c, d = 1;
	cin >> a >> b >> c;
	insert(d);
	for(int i = 1; i <= 2000000; ++i)
	{
		d = ((long long)a*d+d%b)%c;
		if(count(d) == 1)
		{
			cout << i;
			return 0;
		}
		else
			insert(d);
	}
	cout << -1;
	return 0;
}
  • 写法2:实现HashSet类,链表中结点地址为Node*类型
cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define N 2000003
struct Hash
{
	unsigned operator () (int key)
	{
		return key%N;
	}
};
template<class T, class HashFunc>
struct HashSet//开散列 
{
    struct Node 
    {
        T key;
        Node *next = nullptr;
    } node[N], *p = node, *data[N] = {};
    HashFunc hash;
    void insert(T key)
    {//头插法 
    	if(count(key) == 1)//如果哈希表中已经存在key,则不插入 
    		return;
    	int h = hash(key);
		Node *np = ++p;
		np->key = key;;
		np->next = data[h];
		data[h] = np; 
    }
    int count(T key)//获取关键字key的个数 
    {
    	int h = hash(key);
		for(Node *i = data[h]; i != nullptr; i = i->next)
			if(i->key == key)
				return 1;
		return 0;
    }
};
HashSet<int, Hash> hs; 
int main()
{
	
	int a, b, c, d = 1;
	cin >> a >> b >> c;
	hs.insert(d);
	for(int i = 1; i <= 2000000; ++i)
	{
		d = ((long long)a*d+d%b)%c;
		if(hs.count(d) == 1)
		{
			cout << i;
			return 0;
		}
		else
			hs.insert(d);
	}
	cout << -1;
	return 0;
}
相关推荐
Charlie_lll15 分钟前
力扣解题-移动零
后端·算法·leetcode
chaser&upper16 分钟前
矩阵革命:在 AtomGit 解码 CANN ops-nn 如何构建 AIGC 的“线性基石”
程序人生·算法
weixin_4997715525 分钟前
C++中的组合模式
开发语言·c++·算法
iAkuya1 小时前
(leetcode)力扣100 62N皇后问题 (普通回溯(使用set存储),位运算回溯)
算法·leetcode·职场和发展
近津薪荼1 小时前
dfs专题5——(二叉搜索树中第 K 小的元素)
c++·学习·算法·深度优先
xiaoye-duck1 小时前
吃透 C++ STL list:从基础使用到特性对比,解锁链表容器高效用法
c++·算法·stl
松☆1 小时前
CANN与大模型推理:在边缘端高效运行7B参数语言模型的实践指南
人工智能·算法·语言模型
_F_y1 小时前
C++重点知识总结
java·jvm·c++
java干货1 小时前
为什么 “File 10“ 排在 “File 2“ 前面?解决文件名排序的终极算法:自然排序
开发语言·python·算法
皮皮哎哟1 小时前
数据结构:嵌入式常用排序与查找算法精讲
数据结构·算法·排序算法·二分查找·快速排序