hihocoder1260,1261 (HASH经典题)
这两题比赛做的时候各种卡,太久没有写过这种类型的题目了。各种细节想不清楚。 赛后看下网上大部分题解的代码,发现大部分都是直接用TRIE+暴力直接搞的--!,随便找了份代码发现有些数据这种做法是超时的,比如n=m=1,然后下面两行长度为100000的全为a的字符串。明显直接暴力DFS复杂度为n*n.
比赛的时候,还想用26*100000*log(n)然后用STL来去重复,结果直接超时果真STL还是太耗时了。。。
1260解法:
因为字符串集合S中N个字符串是两两不同的(这点比较关键,利用这点可以减少代码量),所以对S中得N个字符进行HASH处理(可以只得到HASH值不建HASH表,查询时候用二分)。然后对于需要查询的M个字符串,因为这M个字符串总长是10^5,所以在每个字符串每一位暴力插入(‘a’-‘z’),也就是要枚举26*10^5种情况,用一次预处理可以使得每次HASH操作为O(1),最后对这26*10^5种情况到HASH表里面去找。这里还有一个去重复的小技巧,对于待查询字符串m,如果出现的序号是k,则每次到HASH表去找时,查找到得时候用一个数组保存序号k,下次m再找到到时则忽略。
直接上大神的代码:
#include<iostream> #include<cmath> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; unsigned long long x[11000],key=10007,Key[110000],pre[110000],ne[110000]; char ch[110000]; int n,m,pd[11000],sign; int find(unsigned long long k){int l=1,r=n+1;while (l<r){int mid=l+r>>1;if (x[mid]==k){if (pd[mid]!=sign){pd[mid]=sign; return 1;} else return 0;}if (x[mid]>k) r=mid; else l=mid+1;}return 0; } int main(){scanf("%d%d",&n,&m);for (int i=1;i<=n;i++){scanf("%s",ch+1); int len=strlen(ch+1);for (int j=1;j<=len;j++) x[i]=x[i]*key+ch[j];}Key[0]=1;for (int i=1;i<=100000;i++) Key[i]=Key[i-1]*key;sort(x+1,x+n+1);for (;m;m--){scanf("%s",ch+1); int len=strlen(ch+1); int ans=0; sign++;for (int j=1;j<=len;j++) pre[j]=pre[j-1]*key+ch[j];ne[len+1]=0;for (int j=len;j;j--) ne[j]=ne[j+1]+ch[j]*Key[len-j];for (int i=0;i<=len;i++)for (int j='a';j<='z';j++){unsigned long long now=pre[i]*Key[len-i+1]+j*Key[len-i]+ne[i+1];ans+=find(now);}printf("%d\n",ans);}return 0; }
View Code
再附上我的又乱又长的代码:
// // main.cpp // hc17 // // Created by 陈加寿 on 15/12/27. // Copyright (c) 2015年 chenhuan001. All rights reserved. // #include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <map> #include <set> #include <string> #include <algorithm> using namespace std; #define K 31 unsigned long long myhash[10010]; char str[100100]; unsigned long long g[100100]; int n,m;int tsave[10010]; int tcnt; int tmark[10010];map<unsigned long long,int> mhash; set<unsigned long long> mark;int myfind(unsigned long long x) {//找到x在myhash中出现的次数int b=1,d=n;while(b<d){int mid=(b+d)/2;if( x <= myhash[mid] )d = mid;else b = mid+1;}if(myhash[b]!=x || tmark[b]==1) return 0;tmark[b]=1;tsave[ tcnt++ ]=b;return 1;int tb=b;b=1,d=n;while(b<d){int mid=(b+d+1)/2;if( x >= myhash[mid] )b = mid;else d= mid-1;}return b-tb+1; }int main() {scanf("%d%d",&n,&m);//mhash.clear();for(int i=1;i<=n;i++){scanf("%s",str);unsigned long len=strlen(str);unsigned long long tmp=1;unsigned long long sum=0;for(int j=0;j<len;j++){sum += tmp*(str[j]-'a'+1);tmp = tmp*K;}//mhash[sum]++;myhash[ i ] = sum;}sort(myhash+1,myhash+n+1);memset(tmark,0,sizeof(tmark));for(int i=0;i<m;i++){//mark.clear();tcnt=0;scanf("%s",str);int len=strlen(str);unsigned long long tmp=1;for(int j=0;j<len;j++){g[j] = tmp*(str[j]-'a'+1);tmp = tmp*K;}for(int j=len-2;j>=0;j--){g[j] += g[j+1];}g[len]=0;int ans=0;tmp = 1;unsigned long long nw=0;for(int j=-1;j<len;j++){for(int p=1;p<=26;p++){unsigned long long tt=nw+p*tmp+g[j+1]*K;if(myfind(tt)==1){ans++;}}nw += tmp*(str[j+1]-'a'+1);tmp *=K;}for(int j=0;j<tcnt;j++)tmark[ tsave[j] ]=0;printf("%d\n",ans);}return 0; }
View Code
1261解法:
这题有个十分关键的思路,在比赛的时候没有想到。--! 真是蒟蒻。
假设有字符串s和字符串t,如果s要恰好添加两个字符变成t,普通的思维至少得要26*len(s)^2次操作才能完成。但是用两边向中心的经典思考方式,于是就可以在s中添加一个字符,从t中删除一个字符。使用HASH复杂度变为len(s)*26。
同理剩下来两种情况。
#include <iostream> #include <stdio.h> #include <string.h> #include <vector> #include <algorithm> using namespace std; #define HASHN 5000007 #define INF 10000000#define K 31 typedef unsigned long long ull;vector<ull>s[10100]; vector<ull>t[10100];//不需要二分,不需要排序。struct HashNode {int next;ull key;//防止冲突int id; }hashnode[3000000];int pre[ HASHN ],cnt; int ansans[100100][3][3];void hash_insert(ull key,int id) {int hashkey = key%HASHN;int num=0;for(int p=pre[hashkey];p!=-1;p = hashnode[p].next){ull nkey = hashnode[p].key ;int nid = hashnode[p].id ;if( nkey == key ){if(id==nid) return ;num++;if(num>=3) return ;//有三个了,直接返回. }}//没有找到相同的,或者相同数目不超过三个,则插入hashnode[cnt].key = key;hashnode[cnt].id = id;hashnode[cnt].next = pre[hashkey];pre[ hashkey ] = cnt++; }void update(int s[3],int x) {if(x==s[0]||x==s[1]||x==s[2]) return ;if(x<s[0]){s[2]=s[1];s[1]=s[0];s[0]=x;}else if(x<s[1]){s[2]=s[1];s[1]=x;}else if(x<s[2]) s[2]=x; }void myfind(ull x,int s[3]) {//找到x在myhash中出现的次数int hashkey = x%HASHN;for(int p=pre[hashkey];p!=-1;p=hashnode[p].next){ull nkey = hashnode[p].key ;int nid = hashnode[p].id ;if(nkey==x){update(s,nid);}}return ; }int main(int argc, const char * argv[]) {int n,m;scanf("%d%d",&n,&m);char str[100100];unsigned long len;for(int i=0;i<n;i++){scanf("%s",str);len=strlen(str);for(int j=0;j<len;j++)s[i].push_back(str[j]-'a'+1);}for(int i=0;i<m;i++){scanf("%s",str);unsigned long len=strlen(str);for(int j=0;j<len;j++)t[i].push_back(str[j]-'a'+1);}//第一个问题。t添加两个字母,等价于s删除一个,t添加一个//第一步,将s进行hashcnt=0;memset(pre,-1,sizeof(pre));ull savetmp[100100];for(int i=0;i<n;i++){len = s[i].size();ull tmp=1;for(int j=1;j<len;j++){savetmp[j] = tmp*s[i][j];tmp *= K;}savetmp[len] = 0;for(int j=len-1;j>=1;j--)savetmp[j] += savetmp[j+1];tmp=1;ull sum=0;for(int j=0;j<len;j++)//删除第j个点 {hash_insert(sum+savetmp[j+1],i);sum += s[i][j]*tmp;tmp *= K;}}int ans[3];/*for(int i=0;i<nodecnt;i++){printf("nodecnt%d : key=%lld id=%d\n",i,g[i].key,g[i].id);}*/for(int i=0;i<m;i++){len = t[i].size();ull tmp=K;for(int j=0;j<len;j++){savetmp[j] = tmp*t[i][j];tmp *= K;}savetmp[len] = 0;for(int j=len-1;j>=0;j--)savetmp[j] += savetmp[j+1];ans[0]=ans[1]=ans[2]=INF;ull sum=0;tmp=1;for(int j=0;j<=len;j++){for(int k=1;k<=26;k++){myfind(sum+k*tmp+savetmp[j],ans);}sum += tmp*t[i][j];tmp *= K;}for(int j=0;j<3;j++){if(ans[j]!=INF) ansans[i][0][j]=ans[j]+1;else ansans[i][0][j]=-1;}//printf("\n"); }//修改两个的时候。cnt=0;memset(pre,-1,sizeof(pre));for(int i=0;i<n;i++){len = s[i].size();ull tmp=K;for(int j=1;j<len;j++){savetmp[j] = tmp*s[i][j];tmp *= K;}savetmp[len] = 0;for(int j=len-1;j>=1;j--)savetmp[j] += savetmp[j+1];tmp=1;ull sum=0;for(int j=0;j<len;j++)//修改第j个点 {for(int k=1;k<=26;k++)hash_insert(sum+tmp*k+savetmp[j+1],i);sum += s[i][j]*tmp;tmp *= K;}}/*for(int i=0;i<nodecnt;i++){printf("nodecnt%d : key=%lld id=%d\n",i,g[i].key,g[i].id);}*/for(int i=0;i<m;i++){len = t[i].size();ull tmp=1;for(int j=0;j<len;j++){savetmp[j] = tmp*t[i][j];tmp *= K;}savetmp[len] = 0;for(int j=len-1;j>=0;j--)savetmp[j] += savetmp[j+1];ans[0]=ans[1]=ans[2]=INF;ull sum=0;tmp=1;for(int j=0;j<len;j++){for(int k=1;k<=26;k++){myfind(sum+k*tmp+savetmp[j+1],ans);}sum += tmp*t[i][j];tmp *= K;}for(int j=0;j<3;j++){if(ans[j]!=INF) ansans[i][1][j]=ans[j]+1;else ansans[i][1][j]=-1;}}//删除两个cnt=0;memset(pre,-1,sizeof(pre));for(int i=0;i<n;i++){len = s[i].size();ull tmp=K;for(int j=0;j<len;j++){savetmp[j] = tmp*s[i][j];tmp *= K;}savetmp[len] = 0;for(int j=len-1;j>=0;j--)savetmp[j] += savetmp[j+1];tmp=1;ull sum=0;for(int j=0;j<=len;j++)//添加第j个点 {for(int k=1;k<=26;k++)hash_insert(sum+tmp*k+savetmp[j],i);sum += s[i][j]*tmp;tmp *= K;}}/*for(int i=0;i<nodecnt;i++){printf("nodecnt%d : key=%lld id=%d\n",i,g[i].key,g[i].id);}*/for(int i=0;i<m;i++){len = t[i].size();ull tmp=1;for(int j=1;j<len;j++){savetmp[j] = tmp*t[i][j];tmp *= K;}savetmp[len] = 0;for(int j=len-1;j>=1;j--)savetmp[j] += savetmp[j+1];ans[0]=ans[1]=ans[2]=INF;ull sum=0;tmp=1;for(int j=0;j<len;j++){myfind(sum+savetmp[j+1],ans);sum += tmp*t[i][j];tmp *= K;}for(int j=0;j<3;j++){if(ans[j]!=INF) ansans[i][2][j]=ans[j]+1;else ansans[i][2][j]=-1;}}for(int i=0;i<m;i++)for(int j=0;j<3;j++){for(int k=0;k<3;k++)printf("%d ",ansans[i][j][k]);printf("\n");}return 0; }
hihocoder1260,1261 (HASH经典题)相关推荐
- 【数据库原理及应用】经典题库附答案(14章全)——第十四章:分布式数据库系统
[数据库原理及应用]经典题库附答案(14章全)--第一章:数据库基础知识 [数据库原理及应用]经典题库附答案(14章全)--第二章:关系数据库知识 [数据库原理及应用]经典题库附答案(14章全)--第 ...
- 【数据库原理及应用】经典题库附答案(14章全)——第十三章:面向对象程数据库系统
[数据库原理及应用]经典题库附答案(14章全)--第一章:数据库基础知识 [数据库原理及应用]经典题库附答案(14章全)--第二章:关系数据库知识 [数据库原理及应用]经典题库附答案(14章全)--第 ...
- 【数据库原理及应用】经典题库附答案(14章全)——第十二章:数据库技术新发展
[数据库原理及应用]经典题库附答案(14章全)--第一章:数据库基础知识 [数据库原理及应用]经典题库附答案(14章全)--第二章:关系数据库知识 [数据库原理及应用]经典题库附答案(14章全)--第 ...
- 【数据库原理及应用】经典题库附答案(14章全)——第十章:数据库完整性
[数据库原理及应用]经典题库附答案(14章全)--第一章:数据库基础知识 [数据库原理及应用]经典题库附答案(14章全)--第二章:关系数据库知识 [数据库原理及应用]经典题库附答案(14章全)--第 ...
- 【数据库原理及应用】经典题库附答案(14章全)——第九章:数据库安全性
[数据库原理及应用]经典题库附答案(14章全)--第一章:数据库基础知识 [数据库原理及应用]经典题库附答案(14章全)--第二章:关系数据库知识 [数据库原理及应用]经典题库附答案(14章全)--第 ...
- 【数据库原理及应用】经典题库附答案(14章全)——第八章:数据库并发控制
[数据库原理及应用]经典题库附答案(14章全)--第一章:数据库基础知识 [数据库原理及应用]经典题库附答案(14章全)--第二章:关系数据库知识 [数据库原理及应用]经典题库附答案(14章全)--第 ...
- 【数据库原理及应用】经典题库附答案(14章全)——第七章:数据库恢复技术
[数据库原理及应用]经典题库附答案(14章全)--第一章:数据库基础知识 [数据库原理及应用]经典题库附答案(14章全)--第二章:关系数据库知识 [数据库原理及应用]经典题库附答案(14章全)--第 ...
- 【数据库原理及应用】经典题库附答案(14章全)——第六章:关系数据库设计过程
[数据库原理及应用]经典题库附答案(14章全)--第一章:数据库基础知识 [数据库原理及应用]经典题库附答案(14章全)--第二章:关系数据库知识 [数据库原理及应用]经典题库附答案(14章全)--第 ...
- 【数据库原理及应用】经典题库附答案(14章全)——第五章:关系数据理论
[数据库原理及应用]经典题库附答案(14章全)--第一章:数据库基础知识 [数据库原理及应用]经典题库附答案(14章全)--第二章:关系数据库知识 [数据库原理及应用]经典题库附答案(14章全)--第 ...
最新文章
- 快速排序(快排)--->注释超详细
- Task.Run vs Task.Factory.StartNew
- 原理竟然是这!2021年字节跳动74道高级程序员面试
- 【小白学习C++ 教程】十三、C++命名空间namespace
- 程序员 sql面试_非程序员SQL使用指南
- 多态计算器的开发 c# 1614095334
- python写一个完整的小程序_写一个python小程序
- CSS3最颠覆性的动画效果,基本属性[过渡和2D]
- 推荐几本lisp的书.
- 阶段3 1.Mybatis_01.Mybatis课程介绍及环境搭建_07.环境搭建的注意事项
- python报错 unexpected keyword argument ‘categories‘
- ICRA 2020轨迹预测竞赛冠军的方法总结
- 计算机简单的办公操作,电脑操作掌握这15种快捷键技巧,你就是办公高手!
- 电信大数据治理与质量管理
- 用docker安装tomcat并实现目录映射端口映射输入ip地址测试网页连接
- 也许通过社群找工作,是未来的趋势。
- OpenCV目标追踪
- ctf MISC writeup
- java相对路径上上级_关于上级目录与上上级目录的表示相对路径
- 微信信息处理 微信公众平台开发教程(1)