137. 雪花雪花雪花

有N片雪花,每片雪花由六个角组成,每个角都有长度。

第i片雪花六个角的长度从某个角开始顺时针依次记为ai,1,ai,2,…,ai,6。

因为雪花的形状是封闭的环形,所以从任何一个角开始顺时针或逆时针往后记录长度,得到的六元组都代表形状相同的雪花。

例如ai,1,ai,2,…,ai,6和ai,2,ai,3,…,ai,6,ai,1

就是形状相同的雪花。

ai,1,ai,2,…,ai,6和ai,6,ai,5,…,ai,1

也是形状相同的雪花。

我们称两片雪花形状相同,当且仅当它们各自从某一角开始顺时针或逆时针记录长度,能得到两个相同的六元组。

求这N片雪花中是否存在两片形状相同的雪花。

输入格式

第一行输入一个整数N,代表雪花的数量。

接下来N行,每行描述一片雪花。

每行包含6个整数,分别代表雪花的六个角的长度(这六个数即为从雪花的随机一个角顺时针或逆时针记录长度得到)。

同行数值之间,用空格隔开。

输出格式

如果不存在两片形状相同的雪花,则输出:

No two snowflakes are alike.

如果存在两片形状相同的雪花,则输出:

Twin snowflakes found.

数据范围

1≤n≤100000,

0≤ai,j<10000000

输入样例:

2

1 2 3 4 5 6

4 3 2 1 6 5

输出样例:

Twin snowflakes found.

#include <iostream>
#include <algorithm>
#include <cstring> using namespace std; const int N = 100010; int n;
int snows[N][6], idx[N]; bool cmp_array(int a[], int b[]) //判断两个数大小 a是不是小于b
{
for(int i = 0; i < 6; i++)
if(a[i] > b[i])
return false;
else if(a[i] < b[i])
return true;
return false;
} bool cmp(int a, int b)
{
return cmp_array(snows[a], snows[b]);
} void get_min(int a[]) //最小表示法
{
static int b[12];
for(int i = 0; i < 12; i++) b[i] = a[i % 6]; //首先把a[i]复制2遍 int i = 0, j = 1, k; //最开始比较第0个和第一个 k表示序列长度
while(i < 6 && j < 6)
{
for(k = 0; k < 6 && b[i + k] == b[j + k]; k ++);
if(k == 6) break; //说明i和j每一位都相同
if(b[i + k] > b [j + k]) //大于 可以跳过一段
{
i += k + 1;
if(i == j) i++;
}
else
{
j += k + 1;
if(i == j) j++;
}
}
k = min(i, j); //i和j比较小的那个是最小表示的起点
for(i = 0; i < 6; i++) a[i] = b[i + k];
} int main()
{
scanf("%d", &n);
int snow[6], isnow[6]; for(int i = 0; i < n; i++)
{
for(int j = 0, k = 5; j < 6; j ++, k--)
{
scanf("%d",&snow[j]);
isnow[k] = snow[j]; //逆序
}
get_min(snow); //把snow变成最小表示
get_min(isnow); if(cmp_array(snow, isnow)) memcpy(snows[i], snow, sizeof snow);
else memcpy(snows[i], isnow, sizeof isnow); idx[i] = i;
}
sort(idx, idx + n, cmp); //排序索引 bool flag = false; //判断两个序列是否相等
for(int i = 1; i < n; i++)
if(!cmp(idx[i - 1], idx[i]) && !cmp(idx[i], idx[i - 1]) ) //cmp判断idx[i-1]是不是小于idx[i] 加个非就是 大于等于 && i >= i-1
{
//相等
flag = true;
break;
}
if(flag) puts("Twin snowflakes found.");
else puts("No two snowflakes are alike.");
return 0;
}

138. 兔子与兔子

很久很久以前,森林里住着一群兔子。

有一天,兔子们想要研究自己的 DNA 序列。

我们首先选取一个好长好长的 DNA 序列(小兔子是外星生物,DNA 序列可能包含 26 个小写英文字母)。

然后我们每次选择两个区间,询问如果用两个区间里的 DNA 序列分别生产出来两只兔子,这两个兔子是否一模一样。

注意两个兔子一模一样只可能是他们的 DNA 序列一模一样。

输入格式

第一行输入一个 DNA 字符串 S。

第二行一个数字 m,表示 m 次询问。

接下来 m 行,每行四个数字 l1,r1,l2,r2,分别表示此次询问的两个区间,注意字符串的位置从1开始编号。

输出格式

对于每次询问,输出一行表示结果。

如果两只兔子完全相同输出 Yes,否则输出 No(注意大小写)。

数据范围

1≤length(S),m≤1000000

输入样例:

aabbaabb

3

1 3 5 7

1 3 6 8

1 2 1 2

输出样例:

Yes

No

Yes

#include <iostream>
#include <string.h> using namespace std; typedef unsigned long long ULL;
const int N = 1000010, base = 131; char str[N];
ULL h[N], p[N]; ULL get(int l, int r)
{
return h[r] - h[l - 1] * p[r - l + 1]; //O(1)的时间求任何字符串的hash值
} int main()
{
scanf("%s", str + 1);
int n = strlen(str + 1); p[0] = 1; //表示131的0次方 = 1
for(int i = 1; i <= n; i++)
{
h[i] = h[i - 1] * base + str[i] - 'a' + 1;
p[i] = p[i - 1] * base;
} int m;
cin >> m;
while(m --)
{
int l1, r1, l2, r2;
scanf("%d%d%d%d", &l1, &r1, &l2, &r2);
if(get(l1, r1) == get(l2, r2)) puts("Yes"); //判断前后两段的hash是不是一样
else puts("No");
}
return 0;
}

139. 回文子串的最大长度

如果一个字符串正着读和倒着读是一样的,则称它是回文的。

给定一个长度为N的字符串S,求他的最长回文子串的长度是多少。

输入格式

输入将包含最多30个测试用例,每个测试用例占一行,以最多1000000个小写字符的形式给出。

输入以一个以字符串“END”(不包括引号)开头的行表示输入终止。

输出格式

对于输入中的每个测试用例,输出测试用例编号和最大回文子串的长度(参考样例格式)。

每个输出占一行。

输入样例:

abcbabcbabcba

abacacbaaaab

END

输出样例:

Case 1: 13

Case 2: 6

#include <iostream>
#include <string.h>
#include <algorithm> using namespace std; typedef unsigned long long ULL;
const int N = 2000010, base = 131; //因为要将偶数转为奇数 在每两个之间加# 所以长度要乘二 二百万 char str[N];
ULL hl[N], hr[N], p[N]; // hl是正序hash值,hr是逆序hash值 p[N]存的是base的多少次方 int get(ULL h[], int l, int r) //求某个子串的hash值
{
return h[r] - h[l - 1] * p[r - l + 1];
} int main()
{
int T = 1;
while(scanf("%s", str + 1), strcmp(str + 1, "END")) //到END 结束
{
int n = strlen(str + 1); //长度 for(int i = n * 2; i > 0; i -= 2) //在每两个之间加#
{
str[i] = str[i / 2]; //拉伸
str[i - 1] = 'z' + 1; //a-z是26 赋值成27
} n *= 2; //长度乘二
// puts(str + 1); p[0] = 1; //131的0次方
for(int i = 1, j = n; i <= n; i++, j--) //计算正序逆序hash值
{
hl[i] = hl[i - 1] * base + str[i] - 'a' + 1;
hr[i] = hr[i - 1] * base + str[j] - 'a' + 1;
p[i] = p[i - 1] * base;
} int res = 0;
for(int i = 1; i <= n; i++) //枚举中点 二分半径
{
int l = 0, r = min(i - 1, n -i); //半径的最小长度是0, 最大半径是min(i - 1, n - i)
while(l < r)
{
int mid = l + r + 1 >> 1;
if(get(hl, i - mid, i - 1) != get(hr, n - (i + mid) + 1, n - (i + 1) + 1)) r = mid - 1;//左右两边的hash值不一样 说明太大 r = mid - 1
else l = mid; // l = mid 上面求mid 要 + 1 防止出现死循环
} if(str[i - l] <= 'z') res = max(res, l + 1); //字母多一个 a...b
else res = max(res, l); // # 多一个 #...#
}
printf("Case %d: %d\n", T ++, res);
}
return 0;
}

140. 后缀数组

后缀数组 (SA) 是一种重要的数据结构,通常使用倍增或者DC3算法实现,这超出了我们的讨论范围。

在本题中,我们希望使用快排、Hash与二分实现一个简单的O(nlog2n)的后缀数组求法。

详细地说,给定一个长度为 n 的字符串S(下标 0~n-1),我们可以用整数 k(0≤k<n) 表示字符串S的后缀 S(k~n-1)。

把字符串S的所有后缀按照字典序排列,排名为 i 的后缀记为 SA[i]。

额外地,我们考虑排名为 i 的后缀与排名为 i-1 的后缀,把二者的最长公共前缀的长度记为 Height[i]。

我们的任务就是求出SA与Height这两个数组。

输入格式

输入一个字符串,其长度不超过30万。

输出格式

第一行为数组SA,相邻两个整数用1个空格隔开。

第二行为数组Height,相邻两个整数用1个空格隔开,我们规定Height[1]=0。

输入样例:

ponoiiipoi

输出样例:

9 4 5 6 2 8 3 1 7 0

0 1 2 1 0 0 2 1 0 2

#include <iostream>
#include <algorithm>
#include <string.h>
#include <limits.h> using namespace std; typedef unsigned long long ULL;
const int N = 300010, base = 131;
int sa[N]; //后缀下标数组 int n;
char str[N];
ULL h[N], p[N]; //前缀hash值数组 int get(int l, int r)
{
return h[r] - h[l - 1] * p[r - l + 1];
} int get_max_common_prefix(int a, int b) //某两个后缀最长公共长度
{
int l = 0, r = min(n - a + 1, n - b + 1);
while(l < r)
{
int mid = l + r + 1 >> 1;
if(get(a, a + mid - 1) != get(b, b + mid - 1)) r = mid - 1;// 判断前缀后缀是否相同
else l = mid;
}
return l;
} bool cmp(int a, int b)
{
int l = get_max_common_prefix(a, b); //前缀长度
int av = a + l > n ? INT_MIN : str[a + l]; //字符空 赋值一个很小的数
int bv = b + l > n ? INT_MIN : str[b + l]; //***这里 是 加上L
return av < bv;
} int main()
{
scanf("%s", str + 1);
n = strlen(str + 1); //***上面定义了 int n p[0] = 1;
for(int i = 1; i <= n; i++)
{
h[i] = h[i - 1] * base + str[i] - 'a' + 1;
p[i] = p[i - 1] * base;
sa[i] = i;
} sort(sa + 1, sa + 1 + n, cmp); for(int i = 1; i <= n; i++) printf("%d ", sa[i] - 1);
puts("");
for(int i= 1; i <= n; i++) //每两个串之间的公共长度
if(i == 1) printf("0 ");
else printf("%d ", get_max_common_prefix(sa[i - 1], sa[i]));
puts("");
return 0; }

《算法竞赛进阶指南》1.4Hash的更多相关文章

  1. 《算法竞赛进阶指南》0x10 基本数据结构 Hash

    Hash的基本知识 字符串hash算法将字符串看成p进制数字,再将结果mod q例如:abcabcdefg 将字母转换位数字(1231234567)=(1*p9+2*p8+3*p7+1*p6+2*p5 ...

  2. bzoj 1787 && bzoj 1832: [Ahoi2008]Meet 紧急集合(倍增LCA)算法竞赛进阶指南

    题目描述 原题连接 Y岛风景美丽宜人,气候温和,物产丰富. Y岛上有N个城市(编号\(1,2,-,N\)),有\(N-1\)条城市间的道路连接着它们. 每一条道路都连接某两个城市. 幸运的是,小可可通 ...

  3. POJ1639 算法竞赛进阶指南 野餐规划

    题目描述 原题链接 一群小丑演员,以其出色的柔术表演,可以无限量的钻进同一辆汽车中,而闻名世界. 现在他们想要去公园玩耍,但是他们的经费非常紧缺. 他们将乘车前往公园,为了减少花费,他们决定选择一种合 ...

  4. 算法竞赛进阶指南 0x00 基本算法

    放在原来这个地方不太方便,影响阅读体验.为了读者能更好的刷题,另起一篇随笔. 0x00 基本算法 0x01 位运算 [题目][64位整数乘法] 知识点:快速幂思想的灵活运用 [题目][最短Hamilt ...

  5. 算法竞赛进阶指南--快速幂,求a^b mod p

    // 快速幂,求a^b mod p int power(int a, int b, int p) { int ans = 1; for (; b; b >>= 1) { if (b &am ...

  6. 算法竞赛进阶指南0x14 Hash

    组成部分: 哈希函数: 链表 AcWing137. 雪花雪花雪花 因为所需要数据量过于大,所以只能以O(n)的复杂度. 所以不可能在实现的过程中一一顺时针逆时针进行比较,所以采用一种合适的数据结构. ...

  7. 《算法竞赛进阶指南》1.6Trie

    142. 前缀统计 给定N个字符串S1,S2-SN,接下来进行M次询问,每次询问给定一个字符串T,求S1-SN中有多少个字符串是T的前缀. 输入字符串的总长度不超过106,仅包含小写字母. 输入格式 ...

  8. 《算法竞赛进阶指南》 1 (P4) a^b 快速幂

    快速幂 #include<cstdio> #include<cmath> #include<iostream> using namespace std; long ...

  9. POJ1722 算法竞赛进阶指南 SUBSTRACT减操作

    原题连接 题目描述 给定一个整数数组\(a_1,a_2,-,a_n\). 定义数组第 i 位上的减操作:把\(a_i\)和\(a_{i+1}\)换成\(a_i - a_{i+1}\). 用con(a, ...

随机推荐

  1. I.MX6 Python3 OpenCV

    /************************************************************************* * I.MX6 Python3 OpenCV * ...

  2. bzoj 2565: 最长双回文串 回文自动机

    题目: Description 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为"abc",逆序为"cba",不相同 ...

  3. bzoj 4501: 旅行 01分数规划+概率期望dp

    题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=4501 题解: 首先我们不考虑可以删除边的情况下,如何计算期望边数. 然后我们发现这是个有 ...

  4. oddjob之smooth关闭程序

    java程序的smooth关闭策略可以采用hook跟观察者的模式实现 无限等状态,如果状态出现可以关闭的事件则进行关闭 虚拟机的关闭通过钩子调用关闭,如果关闭失败,在超时时间内强制杀掉jvm 状态类 ...

  5. 装了Ironpython还需要装Python吗?

    IronPython 是一种在 NET 和 Mono 上实现的 Python 语言,由 Jim Hugunin(同时也是 Jython 创造者)所创造.IronPython是优雅的python编程语言 ...

  6. rsync 端口更换(默认873)

    一般使用默认端口的话, 在服务端的启动命令为: /usr/bin/rsync --address=192.168.1.23 --daemon 如果在客户端需要换另外的端口侦听, 则使用 /usr/bi ...

  7. 【转】 Pro Android学习笔记(四二):Fragment(7):切换效果

    目录(?)[-] 利用setTransition 利用setCustomAnimations 通过ObjectAnimator自定义动态效果 程序代码的编写 利用fragment transactio ...

  8. 人物-IT-任正非:任正非

    ylbtech-人物-IT-任正非:任正非 任正非,祖籍浙江省浦江县,1944年10月25日出生于贵州省安顺市镇宁县.华为技术有限公司主要创始人兼总裁. 1963年就读于重庆建筑工程学院(现已并入重庆 ...

  9. java web 基础 json 和 javaBean转化

    github地址: https://github.com/liufeiSAP/JavaWebStudy 实体类: package com.study.demo.domain; import com.f ...

  10. SpringBoot系列(1)

    简介:用来简化新Spring应用的初始搭建以及开发过程:该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置. 特点:1. 创建独立的Spring应用程序2. 嵌入的Tomcat, ...