信息学奥赛一本通 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;
}
相关推荐
折哥的程序人生 · 物流技术专研7 小时前
Java面试85题图解版 · 特别篇:2026后端高频面试题复盘(算法底层逻辑+高并发架构设计全解析,附Java实战代码)
java·网络·数据库·算法·面试
玖玥拾8 小时前
C/C++ 基础笔记(十四)多态与模板编程
c语言·c++·多态·模板
想吃火锅10058 小时前
【leetcode】14.最长公共前缀js
算法·leetcode·职场和发展
Roann_seo%8 小时前
C++文件操作完全指南:从文本读写到二进制文件处理
开发语言·c++
坚果派·白晓明9 小时前
【鸿蒙PC】SDL3 适配:AtomCode + Skills 快速集成 NAPI 测试工具
c++·华为·ai编程·harmonyos·atomcode
云絮.9 小时前
数据库操作
数据库·mysql·算法·oracle
小林ixn10 小时前
LeetCode 206. 反转链表(迭代 + 递归详解)
算法·leetcode·链表
凡人叶枫10 小时前
Effective C++ 条款17:以独立语句将 newed 对象置入智能指针
java·linux·开发语言·c++·算法
凡人叶枫11 小时前
Effective C++ 条款16:成对使用 new 和 delete 时要采取相同形式
开发语言·c++·effective c++
菜鸟‍11 小时前
LeetCode 1 27 和 704 || 两数之和 移除元素 二分查找
算法·leetcode·职场和发展