COGS 902 乐曲主题 题解 & hash入门贺

【题意】

给定一个长为n的序列,元素都是不超过88的正整数,求序列中主题的最大长度。

所谓主题是指在序列中出现了至少两次并且不相交的子串。特别的,主题可以变调,也就是说如果一个子串全部加上或减去一个数后与另一个子串相同,那么也认为它们是相同的。

对于100%的数据,n<=5000。

【解法】

所谓的变调不过是升降趋势相同,直接来一发差分就好。

答案显然有单调性,长度越长主题越不容易出现,因此可以二分答案,每次只要查询长为ans的子串中是否存在相同且不相交的两个子串即可。

查询子串是否相同可以用哈希实现,这样只要O(n)预处理一发h数组并递推幂取模,取hash值就果断O(1)了。

关于hash的取模,可以直接用unsigned long long自动溢出取模(虽然这是最容易被卡的hash……)。

贴个代码(也不知道出了什么事儿,莫名的折叠不了了,垃圾cnblogs):

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<map>
 5 #define ULL unsigned long long
 6 using namespace std;
 7 const int maxn=5010;
 8 const ULL T=173ull;
 9 void init();
10 ULL hash(int,int);
11 ULL h[maxn],pw[maxn],tmp;
12 int n,a[maxn],L,R,M;
13 bool ok;
14 map<ULL,int>id;
15 int main(){
16 #define MINE
17 #ifdef MINE
18     freopen("theme.in","r",stdin);
19     freopen("theme.out","w",stdout);
20 #endif
21     scanf("%d",&n);
22     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
23     for(int i=n;i;i--)a[i]-=a[i-1];
24     init();
25     L=4;R=n;
26     while(L<=R){
27         M=(L+R)>>1;
28         ok=false;
29         for(int i=1;i+M-1<=n;i++){
30             tmp=hash(i,M);
31             if(id.count(tmp)){
32                 if(id[tmp]<i-M){
33                     ok=true;
34                     break;
35                 }
36             }
37             else id[tmp]=i;
38         }
39         if(ok)L=M+1;
40         else R=M-1;
41     }
42     if(L<5)L=0;
43     printf("%d",L);
44 #ifndef MINE
45     printf("\n-------------------------DONE-------------------------\n");
46     for(;;);
47 #endif
48     return 0;
49 }
50 inline void init(){
51     for(int i=n;i;i--)h[i]=h[i+1]*T+(a[i]+1);
52     pw[0]=1ull;
53     for(int i=1;i<=n;i++)pw[i]=pw[i-1]*T;
54 }
55 inline ULL hash(int x,int l){return h[x]-h[x+l]*pw[l];}
56 /*
57 30
58 25 27 30 34 39 45 52 60 69 79 69 60 52 45 39 34 30 26 22 18
59 82 78 74 70 66 67 64 60 65 80
60 Answer:
61 9
62 */

【hash相关】

虽说是抄的蓝书的hash……但不管怎么说自己算是会写hash了……好感动……

如果字符串给定,询问的串都是它的子串,那么可以O(n)预处理,O(1)查询。

具体来说,定义后缀hash函数为

hi=Tn-i+1si+Tn-isi+1+……+sn,其中T代表字符集大小。

那么利用秦九韶大法,有如下递推式:

hi=hi+1*T+si

然后就可以happy的O(n)推出所有h值啦。

查询的时候,记以x开头,长为l的子串的hash值为hash(x,l),那么有

hash(x,l)=Tlsx+Tl-1sx+1+……+sx+l-1

由上面h函数的公式,可以推出

hash(x,l)=hx-Tlhx+l

然后就可以happy的O(1)查询啦。

时间: 2024-07-29 05:24:05

COGS 902 乐曲主题 题解 & hash入门贺的相关文章

【POJ1743】Musical Themes 乐曲主题 后缀数组、 (也可以用hash+二分做的~)

题意: 1829: Musical Themes 乐曲主题 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 42  Solved: 15 [Submit][Status][Web Board] Description 我们用N(1 <= N <=5000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,每个数表示钢琴上的一个键.很不幸这种表示旋律的方法忽略了音符的时值,但这项编程任务是关于音高的,与时值无关. 许多作曲家围绕一个重

poj1200-Crazy Search(hash入门经典)

Hash:一般是一个整数.就是说通过某种算法,可以把一个字符串"压缩" 成一个整数.一,题意: 给出两个数n,nc,并给出一个由nc种字符组成的字符串.求这个字符串中长度为n的不同子串有多少种?二,思路: 1.这个题不用匹配,因为不高效. 2.将长度为n的子串看作n位的nc进制数,将问题转化为共有多少种十进制数字. 3.哈希时,每一个字符都对应这0 ~ nc-1的一个数字.三,步骤: 1.给nc个字母编号:0 ~ nc-1 hashArray[ch[i]] = k++; 2.明确每n个

Hash入门

HDU1425 Problem Description 给你n个整数,请按从大到小的顺序输出其中前m大的数. Input 每组测试数据有两行,第一行有两个数n,m(0<n,m<1000000),第二行包含n个各不相同,且都处于区间[-500000,500000]的整数. Output 对每组测试数据按从大到小的顺序输出前m大的数. Sample Input 5 3 3 -35 92 213 -644 Sample Output 213 92 3 一开始看到这题,我就直接用sort排序,然后输出

COGS 08-备用交换机 题解——S.B.S.

8. 备用交换机 ★★   输入文件:gd.in   输出文件:gd.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] n个城市之间有通讯网络,每个城市都有通讯交换机,直接或间接与其它城市连接.因电子设备容易损坏,需给通讯点配备备用交换机.但备用交换机数量有限,不能全部配备,只能给部分重要城市配置.于是规定:如果某个城市由于交换机损坏,不仅本城市通讯中断,还造成其它城市通讯中断,则配备备用交换机.请你根据城市线路情况,计算需配备备用交换机的城市个数,及需配备备用交换

LDA主题模型三连击-入门/理论/代码

本文将从三个方面介绍LDA主题模型--整体概况.数学推导.动手实现. 关于LDA的文章网上已经有很多了,大多都是从经典的<LDA 数学八卦>中引出来的,原创性不太多. 本文将用尽量少的公式,跳过不需要的证明,将最核心需要学习的部分与大家分享,展示出直观的理解和基本的数学思想,避免数学八卦中过于详细的推导.最后用python 进行实现. [TOC] 概况 第一部分,包括以下四部分. 为什么需要 LDA是什么 LDA的应用 LDA的使用 为什么需要 挖掘隐含语义信息.一个经典的例子是 "

【题解】入门

题目描述 不是任何人都可以进入桃花岛的,黄药师最讨厌象郭靖一样呆头呆脑的人.所以,他在桃花岛的唯一入口处修了一条小路,这条小路全部用正方形瓷砖铺设而成.有的瓷砖可以踩,我们认为是安全的,而有的瓷砖一踩上去就会有喷出要命的毒气,那你就死翘翘了,我们认为是不安全的.你只能从一块安全的瓷砖上走到与他相邻的四块瓷砖中的任何一个上,但它也必须是安全的才行. 由于你是黄蓉的朋友,她事先告诉你哪些砖是安全的.哪些砖是不安全的,并且她会指引你飞到第1块砖上(第1块砖可能在任意安全位置),现在她告诉你进入桃花岛的

[USACO5.1]乐曲主题Musical Themes

题目链接:戳我 Emmm......hash怎么做啊不会啊 这里是SA后缀数组版本的 就是先两两做差分,作为要处理后缀的数组.普通地求出来h数组之后,我们二分这个答案,然后判定是否合法就行了.是否合法即\(min(sa[j])+h[i]<max(sa[j]),j<=i\) 代码如下: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include

COGS 2434 暗之链锁 题解

[题意] 给出一个有n个点的无向图,其中有n-1条主要边且这些主要边构成一棵树,此外还有m条其他边,求斩断原图的一条主要边和一条其他边使得图不连通的方案数. 注意,即使只斩断主要边就可以使得原图不连通,你仍然需要继续斩断一条其他边才能成为一种方案. [解法] 考虑到原图的一个性质:使得原图不连通的方案只有以下两种情况: 1.主要边是原图的桥 2.主要边和附加边连接的两个连通块只有这两条边相连 显然每个1产生的方案都有m种,每个2产生的方案只有一种. 考虑到原图的主要边构成一棵树并且只有主要边可能

POJ2752题解——KMP入门

题目链接:http://poj.org/problem?id=2752 The little cat is so famous, that many couples tramp over hill and dale to Byteland, and asked the little cat to give names to their newly-born babies. They seek the name, and at the same time seek the fame. In ord