信息学奥赛一本通 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;
}
相关推荐
草莓熊Lotso2 小时前
Qt 控件美化与交互进阶:透明度、光标、字体与 QSS 实战
android·java·开发语言·c++·人工智能·git·qt
永远都不秃头的程序员(互关)2 小时前
【决策树深度探索(二)】决策树入门:像人类一样决策,理解算法核心原理!
算法·决策树·机器学习
HaiLang_IT2 小时前
基于图像处理与深度学习的油橄榄品种和成熟度检测算法研究
图像处理·深度学习·算法
YuTaoShao2 小时前
【LeetCode 每日一题】3510. 移除最小数对使数组有序 II
linux·算法·leetcode
青山是哪个青山2 小时前
C++ 核心基础与面向对象 (OOP)
开发语言·c++
小明同学012 小时前
[C++进阶]深入理解二叉搜索树
开发语言·c++·git·visualstudio
点云SLAM2 小时前
C++std::enable_if_t 与 std::is_same_v使用
c++·模板元编程·c++ 类型萃取·enable_if_t·is_same_v
C+++Python2 小时前
C++ vector
开发语言·c++·算法
2401_841495642 小时前
【LeetCode刷题】K 个一组翻转链表
数据结构·python·算法·leetcode·链表·翻转链表·迭代翻转