2013 Asia Regional Changchun I 题,HDU(4821),Hash
Posted 树的种子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2013 Asia Regional Changchun I 题,HDU(4821),Hash相关的知识,希望对你有一定的参考价值。
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=4821
解题报告:搞了很久,总算搞出来了,还是参考了一下网上的解法,的确很巧,和上次湘潭的比赛中的一个求平方和的题目思路很类似。
首先说一下hash,简单来说就是y = hash(x),有很多函数,可以参考这里:https://www.byvoid.com/blog/string-hash-compare/
然后,我用的是这个:写法简单,而且重复的可能较小。
// BKDR Hash Function unsigned int BKDRHash(char *str) { unsigned int seed = 131; // 31 131 1313 13131 131313 etc.. unsigned int hash = 0; while (*str) { hash = hash * seed + (*str++); } return (hash & 0x7FFFFFFF); }
然后回到这个题目:
3W,4RE,3TLE,首先wa的原因:循环次数少了一,<=slen,超时没办法,只能优化了。
下面是没有优化的代码,每个子串求一下hash.
/* #include <cstdio> #include <cstring> #include <string> using namespace std; const int inf = 2000000; bool t[2000000]; int Hash[100005]; long long myhash(char *str) { int seed = 31; long long hash = 0; while (*str) hash =( hash * seed + (*str++)-\'a\' + 1) %inf ; return hash; } int main() { int m,l; while(scanf("%d%d",&m,&l)!=EOF) { char str[100005]; scanf("%s",str); int len = strlen(str); int ans = 0; int k = 0; for(int i=0; i+m<len; i++) { char temp[100005]; for(int j=0; j<l; j++) temp[j] = str[i+k*m+j]; temp[l] = \'\\0\'; long long hashs = myhash(temp); Hash[i+k*m] = myhash() } for(int i=0; i<l&&i+m*l<=len; i++) { memset(t,false,sizeof(t)); bool flag = true; for(int k = 0; k<m; k++) { char temp[100005]; for(int j=0; j<l; j++) temp[j] = str[i+k*m+j]; temp[l] = \'\\0\'; long long hashs = myhash(temp); if(t[hashs]) { flag = false; break; } t[hashs] = true; } if(flag) ans++; } printf("%d\\n",ans); } return 0; } */
优化方案。上图比较好!!!
优化的位置就是成段删掉,成段添加。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <map> using namespace std; const int MAXN = 100010; const unsigned long long base = 31; unsigned long long nbase[MAXN],Hash[MAXN]; int n,len,ans,slen; char str[MAXN]; map<unsigned long long, int> mp; int main() { unsigned long long tmp; nbase[0] = 1; for (int i = 1; i <= MAXN; i++) nbase[i] = nbase[i-1] * base; while (scanf("%d%d", &n, &len) != EOF) { scanf("%s", str); slen = strlen(str); Hash[slen] = 0; for (int i = slen-1; i >= 0; i--) Hash[i] = Hash[i+1]*base+str[i]-\'a\'+1; ans = 0; for (int i = 0; i < len && i+n*len <= slen; i++) { mp.clear(); for (int j = i; j < i+n*len; j += len) { tmp = Hash[j] - Hash[j+len]*nbase[len]; mp[tmp]++; } if (mp.size() == n) ans++; for (int j = i+n*len; j+len <= slen; j += len) { tmp = Hash[j-n*len] - Hash[j-(n-1)*len]*nbase[len]; mp[tmp]--; if (mp[tmp] == 0) mp.erase(tmp); tmp = Hash[j] - Hash[j+len]*nbase[len]; mp[tmp]++; if (mp.size() == n) ans++; } } printf("%d\\n", ans); } return 0; }
以上是关于2013 Asia Regional Changchun I 题,HDU(4821),Hash的主要内容,如果未能解决你的问题,请参考以下文章
2012-2013 ACM-ICPC, Asia Tokyo Regional Contest
2019 ICPC Asia Yinchuan Regional
2018 ICPC Asia Jakarta Regional Contest
2019 ICPC Asia Nanjing Regional