2022暑初二信息竞赛学习成果分享2

学习目录2

  • 第二期 (2022/07/17~2022/07/23)
    • Day 7:复习&测试——**树状数组**
      • `Morning`——树状数组复习测试
        • 考试“游记”
        • 题目总结
          • [T83. Count](http://222.180.160.110:1024/contest/2713/problem/1)
          • 理解与感悟
          • [T84. Friend](http://222.180.160.110:1024/contest/2713/problem/2)
          • 理解与感悟
          • [T85. Self-Number](http://222.180.160.110:1024/contest/2713/problem/3)
          • 理解与感悟
          • [T86. 简单题](http://222.180.160.110:1024/contest/2713/problem/4)
      • `Afternoon`——普及组题目练习
    • Day 8:新知——**哈希`Hash`表**
      • `Morning`——哈希`Hash`表新课学习
        • 学习笔记
          • 一、Hash函数
          • 二、哈希表
          • 三、冲突
          • 四、Hash函数的构造方法
          • 五、处理冲突的办法
      • `Morning & Afternoon`——哈希`Hash`表题目练习
        • [T99. 三个朋友](http://222.180.160.110:1024/contest/2650/problem/8)
        • 理解与感悟
    • Day 9:复习&测试——**Hash表**
      • `Morning`——Hash表复习测试
        • 考试“游记”
        • 题目总结
          • [T104. 子串查找](http://222.180.160.110:1024/contest/2724/problem/1)
          • 理解与感悟
          • [T105. friends](http://222.180.160.110:1024/contest/2724/problem/2)
          • 理解与感悟
          • [T106. Match](http://222.180.160.110:1024/contest/2724/problem/3)
          • 理解与感悟
    • Day 10:新知——**图的概念、结构和遍历**
      • `Morning`——图的概念、结构和遍历新课学习
        • 学习笔记
          • 一、定义
          • 二、种类
          • 三、无向图的术语
          • 四、有向图的术语
          • 五、图的表示
          • 六、图的遍历
      • `Morning & Afternoon`——图的概念、结构和遍历题目练习
        • [T113. 树的存储](http://222.180.160.110:1024/contest/2668/problem/1)
        • 理解与感悟
    • Day 11:新知——**最短路**
      • `Morning`——最短路新课学习(一)
        • 学习笔记
          • 一、概念
          • 二、`Floyd`算法
          • 三、`Dijkstra`算法
    • Day 12:新知——**最短路**
      • `Morning`——最短路新课学习(二)
        • 学习笔记
          • 四、`Bellman-Ford`算法
          • 五、`SPFA`算法
  • 第三期 (2022/07/25~2022/07/30)
    • Day 13:复习&测试——**最短路**
      • `Morning`——最短路复习测试
        • 考试“游记”
        • 题目总结
          • [T154. 最短路上的统计](http://222.180.160.110:1024/contest/2755/problem/1)
          • 理解与感悟
          • [T155. ことりのおやつ](http://222.180.160.110:1024/contest/2755/problem/2)
          • 理解与感悟
          • [T156. 新年好](http://222.180.160.110:1024/contest/2755/problem/3)
          • 理解与感悟
          • [T157. 算法导论](http://222.180.160.110:1024/contest/2755/problem/4)
          • 理解与感悟
    • Day 14:新知——**最小生成树**
      • `Morning`——最小生成树新课学习(一)
        • 学习笔记
          • 一、最小生成树
          • 二、`Prim`算法
          • 三、`Kruskal`算法
    • Day 15:复习&测试——**最小生成树**
      • `Morning`——最小生成树复习测试
        • 考试“游记”
        • 题目总结
          • 考试T1. 新的开始
          • 理解与感悟
          • 考试T2. 最小花费
          • 理解与感悟
          • 考试T3. 最小花费
          • 理解与感悟

上一篇 这一篇 下一篇
2022暑初二信息竞赛学习成果分享1 2022暑初二信息竞赛学习成果分享2

第二期 (2022/07/17~2022/07/23)

Day 7:复习&测试——树状数组

Morning——树状数组复习测试

考试“游记”

拿到题目,第一题太la了(这套题他还真是xun啊)

8:25开考。

看了眼第一题,我直接感慨:这是给小升初的做的吗,太水了。10 min, 8:35

第二题,乍一看,不就是一个筛质数的裸题吗?!看我用那珍藏已久的埃氏筛法,搞定这道water题! 15 min, 8:40

第三题题面好长,对于我一个急性子来说,直接放弃!思考了15 min8:55

第四题不就是一个瞎子都能看出来的树状数组题吗!轻轻松松! 15 min, 9:10

第五题,这什么题!四不像——一不像区间DP,二不像暴力枚举,三不像树状数组,四不像贪心…思考了很久! 55 min, 10:05

又回头看第三题,直接用一个暴力法,找出来,对了样例。15 min, 10:20

最后再看第五题,也没有其他办法,直接暴力×2,调了一会儿,时间又匆匆而过。40 min, 11:00

最后25 min,我似乎不再抱有任何希望了,直接touch fish

11:25 收卷。

测评开始… 结果如下。

选手 A B C D E 总分
C2024XSC249 AC 100 AC 100 WA 20 TLE 80 TLE 40 340/500

通过这次第四题的失败,我终于明白:一定要打快读快写

话说,快读快写怎么打的?

int read () {
   
	int f = -1, x = 0;//f表示符号,x表示绝对值
	char ch = getchar ();
	if (ch == '-') {
   //判断负号
		f = -1;
	} else {
   
		x = ch - '0';
	}
	while (1) {
   
		ch = getchar ();
		if (ch >= '0' && ch <= '9') {
   //正在输入数字
			x = 10 * x + ch - '0';
		} else {
   
			break;
		}
	}
	return f * x;//正负性*绝对值
}

void write (int x) {
   
	if (x == '-') {
   //处理负号
		putchar ('-');
		x = -x;
	}
	if (x >= 10) {
   //大于10,递归输出十位及以上数位
		write (x / 10);
	}
	putchar (x % 10 + '0');
}
题目总结
T83. Count

题目描述
某次科研调查时得到了 n n n个自然数,每个数均不超过 1500000000 1500000000 1500000000 1.5 × 1 0 9 1.5 \times 10^9 1.5×109)。已知不相同的数不超过 10000 10000 10000个,现在需要统计这些自然数各自出现的次数,并按照自然数从小到大的顺序输出统计结果。

输入格式
输入包含 n + 1 n+1 n+1行;第一行是整数 n n n,表示自然数的个数;第 2 2 2~ n + 1 n+1 n+1每行一个自然数。

输出格式
输出包含 m m m行( m m m n n n个自然数中不相同数的个数),按照自然数从小到大的顺序输出。每行输出两个整数,分别是自然数和该数出现的次数,其间用一个空格隔开。

样例
样例输入

8
2
4
2
4
5
100
2
100

样例输出

2 3
4 2
5 1
100 2

数据范围与提示
40 % 40\% 40%的数据满足: 1 ≤ n ≤ 1000 1 \le n \le 1000 1n1000

80 % 80\% 80%的数据满足: 1 ≤ n ≤ 50000 1 \le n \le 50000 1n50000

100 % 100\% 100%的数据满足: 1 ≤ n ≤ 200000 1 \le n \le 200000 1n200000

理解与感悟

简单的语法题。

先输入,再排序,最后统计。

#include 
#include 
#include 
using namespace std;

const int MAXN = 2e5 + 5;
int n, a[MAXN], cnt = 1;

int main () {
   
//  freopen ("count.in", "r", stdin);
//  freopen ("count.out", "w", stdout);
	scanf ("%d", &n);
	for (int i = 1; i <= n; i ++) {
   
		scanf ("%d", &a[i]);//输入
	}
	sort (a + 1, a + n + 1);//排序
	for (int i = 1; i <= n; i ++) {
   
		if (a[i + 1] == a[i]) {
   
			cnt ++;//统计并输出
		} else {
   
			printf ("%d %d\n", a[i], cnt);
			cnt = 1;
		}
	}
	return 0;
}
T84. Friend

题目描述
新年快到了,“神仙协会”准备搞一个聚会,已经知道现有会员 N N N人,把会员从 1 1 1 N N N编号,已知凡是和会长是老朋友的,那么该会员的号码肯定只能被自己的号码和 1 1 1整除,否则都是会长新朋友,现在会长想知道究竟有几个新朋友?请你编程序帮会长计算出来。

输入格式
输入数据仅一个数 N N N,表示会员人数。

输出格式
输出新朋友的人数。

样例
样例输入

7

样例输出

3

数据范围与提示
30 % 30\% 30%的数据满足: 1 ≤ n ≤ 10000 1 \le n \le 10000 1n10000

60 % 60\% 60%的数据满足: 1 ≤ n ≤ 500000 1 \le n \le 500000 1n500000

100 % 100\% 100%的数据满足: 1 ≤ n ≤ 2000000 1 \le n \le 2000000 1n2000000

理解与感悟

典型的筛质数题,直接输出 n − 质数个数 n-质数个数 n质数个数即可。

#include 
#include 
#include 
using namespace std;

const int MAXN = 2e6 + 5;
int n, cnt;
bool flag[MAXN];

int main () {
   
//	freopen ("friend.in", "r", stdin);
//	freopen ("friend.out", "w", stdout);
	scanf ("%d", &n);
	for (int i = 2; i <= n; i ++) {
   
		if (flag[i] == 0) {
   
			cnt ++;
			for (int j = 2 * i; j <= n; j += i) {
   //埃氏筛质数法
				flag[j] = 1;
			}
		}
	}
	printf ("%d", n - cnt);//输出
	return 0;
}
T85. Self-Number

题目描述
在1949年印度数学家D. R. Daprekar发现了一类称作Self-Numbers的数。对于每一个正整数 n n n,我们定义 d ( n ) d(n) d(n)为加上它每一位数字的和。例如, d ( 75 ) = 75 + 7 + 5 = 87 d(75)=75+7+5=87 d(75)=75+7+5=87
给定任意正整数 n n n作为一个起点,都能构造出一个无限递增的序列: n , d ( n ) , d ( d ( n ) ) , d ( d ( d ( n ) ) ) n,d(n),d(d(n)),d(d(d(n))) n,d(n),d(d(n)),d(d(d(n))), . . . 例如,如果你从 33 33 33开始,下一个数是 33 + 3 + 3 = 39 33+3+3=39 33+3+3=39,再下一个为 39 + 3 + 9 = 51 39+3+9=51 39+3+9=51,再再下一个为 51 + 5 + 1 = 57 51+5+1=57 51+5+1=57,因此你所产生的序列就像这样: 数字 n n n被称作 d ( n ) d(n) d(n)的发生器。在上面的这个序列中, 33 33 33 39 39 39的发生器, 39 39 39 51 51 51的发生器, 51 51 51 57 57 57的发生器等等。有一些数有超过一个发生器,如 101 101 101的发生器可以使 91 91 91 100 100 100。一个没有发生器的数被称作Self-Number。如前 13 13 13个Self-Number为 1 , 3 , 5 , 7 , 9 , 20 , 31 , 42 , 53 , 64 , 75 , 86 , 97 , . . . 1,3,5,7,9,20,31,42,53,64,75,86,97,... 1,3,5,7,9,20,31,42,53,64,75,86,97,...。我们将第个表示为,所以 a 1 = 1 , a 2 = 3 , a 3 = 5 a_1=1,a_2=3,a_3=5 a1=1,a2=3,a3=5. . .

输入格式
输入包含整数 N , K , s 1 , s 2 , . . . , s K N,K,s_1,s_2,...,s_K N,K,s1,s2,...,sK,其中 1 ≤ N ≤ 1 0 7 , 1 ≤ K ≤ 5000 1 \le N \le 10^7,1 \le K \le 5000 1N107,1K5000,以空格和换行分割。

输出格式
在第一行你需要输出一个数,这个数表示在闭区间 [ 1 , N ] [1, N] [1,N]中Self-Number的数量。第二行必须包含以空格划分的 K K K个数,表示a[s1]. . a[sk],这里保证所有的a[s1]. . a[sk]都小于N,但不一定按顺序排列(例如,如果 N = 100 N=100 N=100 s k s_k sk可以为 1 1 1~ 13 13 13,但不能为 14 14 14,因为 a 14 = 108 > 100 a_{14}=108>100 a14=108>100

样例
样例输入

100 10
1 2 3 4 5 6 7 11 12 13 

样例输出

13
1 3 5 7 9 20 31 75 86 97
理解与感悟

首先按照题目要求依次枚举发生器,并将 d ( n ) d(n) d(n)标记为1。

然后把没有标记成1的数塞进ans[]答案数组里。

最后输出相应的下标即可。

代码

#include 
#include 
#include 
using namespace std;

const int MAXN = 1e7 + 105;
int n, k, s[MAXN], sn[MAXN], cnt;
bool f[MAXN];

int d (int s) {
   
	int ans = s;
	while (s > 0) {
   
		ans += s % 10;
		s /= 10; 
	}
	return ans;
}

int main () {
   
//	freopen ("number.in", "r", stdin);
//	freopen ("number.out", "w", stdout);
	scanf ("%d %d", &n, &k);
	for (int i = 1; i <= k; i ++) {
   
		scanf ("%d", &s[i]);
	}
	for (int i = 1; i <= n; i ++) {
   
		f[d (i)] = 1;//将每一个d[i]的flag值置为1
	}
	for (int i = 1; i <= n; i ++) {
   
		if (f[i] == 0) {
   
			sn[++ cnt] = i;//塞入sn[]数组
		} 
	}
	int c = 1;
	printf ("%d\n", cnt);
	for (int i = 1; i <= k; i ++) {
   
		printf ("%d ", sn[s[i]]);//按照相应下标进行输出
	}
	return 0;
}
T86. 简单题

题目来源:CQOI 2006

有一个 n n n 个元素的数组,每个元素初始均为 0 0 0 。有 m m m 条指令,要么让其中一段连续序列数字反转—— 0 0 0 1 1 1 1 1 1 0 0 0(操作 1 1 1),要么询问某个元素的值(操作 2 2 2)。

例如当 n = 20 n=20 n=20 时, 10 10 10 条指令如下:

操作 回答 操作后的数组
1 1 10 N/A 11111111110000000000
2 6 1 1 1 11111111110000000000
输入格式
第一行包含两个整数 ,表示数组的长度和指令的条数;
以下 行,每行的第一个数 表示操作的种类:

若 ,则接下来有两个数 ,表示区间 的每个数均反转;
若 ,则接下来只有一个数 ,表示询问的下标。
输出格式
每个操作 输出一行(非 即 ),表示每次操作 的回答。

样例
样例输入
20 10
1 1 10
2 6
2 12
1 5 12
2 6
2 15
1 6 16
1 11 17
2 12
2 6
样例输出
1
0
0
0
1
1
数据范围与提示
对于 的数据,;
对于 的数据,,保证 。

Afternoon——普及组题目练习

Day 8:新知——哈希Hash

Morning——哈希Hash表新课学习

学新课有三忌,一忌不听讲,二忌走神,三忌不记笔记。——C2024XSC249

学习笔记
一、Hash函数

指可以根据关键字直接计算出元素所在位置的函数。

二、哈希表

根据设定的哈希函数 Hash(key) 和处理冲突的方法将一组关键字映象到一个有限的连续的地址集(区间)上,并以关键字在地址集中的 “象” 作为记录在表中的存储位置,这种表便称为哈希表,这一映象过程称为哈希造表散列,所得存储位置称为哈希地址散列地址

三、冲突
  1. 定义:不同的元素占用同一个地址的情况叫做冲突。
  2. 发生冲突的因素
    (1) 装填因子 α \alpha α
    装填因子是指哈希表中己存入的元素个数 n n n 与哈希表的大小 m m m 的比值,即 α = n m α=\frac{n}{m} α=mn α α α越小,发生冲突的可能性越小,反之,发生冲突的可能性就越大。但是, α α α太小又会造成大量存贮空间的浪费,因此必须兼顾存储空间和冲突两个方面。
    (2)所构造的哈希函数
    构造好的哈希函数,使冲突尽可能的少。
    (3)解决冲突的方法
    设计有效解决冲突的方法 。.
四、Hash函数的构造方法
  1. 直接定址法
    取关键字或关键字的某个线性函数值为散列地址,即Hash(K)=KHash(K)=a * K + b(其中 a a a b b b为常数)。
    优点:以关键码 key 的某个线性函数值为哈希地址,不会产生冲突。
    缺点:要占用连续地址空间,空间效率低。

  2. 除后余数法 (常用)
    取关键字被不大于散列表表长 m m m 的数 p p p 除后所得的余数为哈希函数。即
    H a s h ( K ) = K m o d    p ( p ≤ m ) Hash(K) = K \mod p (p≤m) Hash(K)=Kmodp(pm)

    ps:经验得知,一般可选 p p p为质数 或 不包含小于 20 20 20的质因子的合数。例如:131, 1331, 13331, ...

  3. 平方取中法
    取关键字平方后的中间几位为哈希函数。因为中间几位与数据的每一位都相关。
    例: 2589 2589 2589的平方值为 6702921 6702921 6702921,可以取中间的 029 029 029为地址。

  4. 数字分析法
    选用关键字的某几位组合成哈希地址。
    选用原则应当是:各种符号在该位上出现的频率大致相同。

  5. 折叠法
    是将关键字按要求的长度分成位数相等的几段,最后一段如不够长可以短些,然后把各段重叠在一起相加并去掉进位,以所得的和作为地址。
    适用于:每一位上各符号出现概率大致相同的情况。
    具体方法:
    移位法:将各部分的最后一位对齐相加(右对齐)。
    间接叠加法:从一端向另一端沿分割界来回折叠后,最后一位对齐相加。
    例:元素 42751896 42751896 42751896,
    移位法: 427 + 518 + 96 = 1041 427+518+96=1041 42751896=1041
    间接叠加法: 42751896 − > 724 + 518 + 69 = 1311 427 518 96 -> 724+518+69 =1311 42751896>724+518+69=1311

  6. 随机数法
    选择一个随机函数,取关键字的随机函数值为它的哈希地址,即Hash (key) = random (key) 其中random为随机函数(random是C语言函数)。
    通常,当关键字长度不等时采用此法构造哈希函数较恰当。
    rand (): 取随机数,以默认种子1来生成,只要种子一样,无论何时何地生成的随机数都一样。
    srand (x): 将随机数的种子改为 x x x
    time (0): 获取当前时间,因为时间一直在变化,所以随机数的值也在变化。
    参考代码:

#include 
#include 
#include 
using namespace std;

int main () {
   
	srand (time (0));
	printf ("%d\n", rand ());
	return 0;
}
  1. 建立Hash ()函数通常考虑的因素
    (1)计算哈希函数所需时间(包括硬件指令的因素);
    (2)关键字的长度;
    (3)哈希表的大小;
    (4)关键字的分布情况;
    (5)记录的查找频率。
五、处理冲突的办法
  1. 开放地址法
    开放地址就是表中尚未被占用的地址,当新插入的记录所选地址已被占用时,即转而寻找其它尚开放的地址。
    (1) 线性探测法
    设散列函数 Hash (K) = K mod m m m m为表长),若发生冲突,则沿着一个探查序列逐个探查(也就是加上一个增量),那么,第i次计算冲突的散列地址为:
    H i = ( H ( K ) + d i ) m o d    m ( d i = 1 , 2 , … , m − 1 ) H_i = (H(K)+d_i) \mod m (d_i=1,2,…,m-1) Hi=(H(K)+di)modm(di=1,2,,m1)
    优点:只要哈希表未被填满,保证能找到一个空地址单元存放有冲突的元素;
    缺点:可能使第 i i i个哈希地址的同义词存入第 i + 1 i+1 i+1 个哈希地址,这样本应存入第 i + 1 i+1 i+1个哈希地
    址的元素变成了第 i + 2 i+2 i+2个哈希地址的同义词,……,因此,可能出现很多元素在相邻的哈希
    地址上“堆积”起来,大大降低了查找效率。
    (2) 二次探测法
    二次探测法对应的探查地址序列的计算公式为:
    H i = ( H ( k ) + d i ) m o d    m H_i = ( H(k) + d_i ) \mod m Hi=(H(k)+di)modm
    其中 d i = 1 2 , − 1 2 , 2 2 , − 2 2 , … , j 2 , − j 2 ( j ≤ m / 2 ) d_i =1^2,-1^2,2^2,-2^2,…,j^2,-j^2 (j≤m/2) di=12,12,22,22,,j2,j2(jm/2)

  2. 链地址法
    基本思想:
    将具有相同哈希地址的记录链成一个单链表,m个哈希地址就设 m个单链表,然后用一个数组将m个单链表的表头指针存储起来,形成一个动态的结构。
    优点:插入、删除方便。
    缺点:占用存储空间多。

  3. 再哈希法
    基本思想:

H i = R H i ( k e y ) ( i = 1 , 2 , 3 , … … , k ) 。 H_i= RH_i(key) (i=1,2,3,……,k)。 Hi=RHi(key)(i=1,2,3,……,k)

   其中,$RH_i()$ 均是不同的哈希函数,即在同义词产生地址冲突时计算另一个哈希函数地址,直到冲突不再发生。
   **优点**:不易产生“聚集”。
   **缺点**:增加了计算时间。
  1. 建立一个公共溢出区
    基本思想:
    假设哈希函数的值域为 [ 0 , m − 1 ] [0,m-1] [0,m1],则设向量 H a s h T a b l e [ 0 , m − 1 ] HashTable[0,m-1] HashTable[0,

你可能感兴趣的:(数据结构,算法,图论,学习,算法)