这两题比赛做的时候各种卡,太久没有写过这种类型的题目了。各种细节想不清楚。 赛后看下网上大部分题解的代码,发现大部分都是直接用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经典题)相关推荐

  1. 【数据库原理及应用】经典题库附答案(14章全)——第十四章:分布式数据库系统

    [数据库原理及应用]经典题库附答案(14章全)--第一章:数据库基础知识 [数据库原理及应用]经典题库附答案(14章全)--第二章:关系数据库知识 [数据库原理及应用]经典题库附答案(14章全)--第 ...

  2. 【数据库原理及应用】经典题库附答案(14章全)——第十三章:面向对象程数据库系统

    [数据库原理及应用]经典题库附答案(14章全)--第一章:数据库基础知识 [数据库原理及应用]经典题库附答案(14章全)--第二章:关系数据库知识 [数据库原理及应用]经典题库附答案(14章全)--第 ...

  3. 【数据库原理及应用】经典题库附答案(14章全)——第十二章:数据库技术新发展

    [数据库原理及应用]经典题库附答案(14章全)--第一章:数据库基础知识 [数据库原理及应用]经典题库附答案(14章全)--第二章:关系数据库知识 [数据库原理及应用]经典题库附答案(14章全)--第 ...

  4. 【数据库原理及应用】经典题库附答案(14章全)——第十章:数据库完整性

    [数据库原理及应用]经典题库附答案(14章全)--第一章:数据库基础知识 [数据库原理及应用]经典题库附答案(14章全)--第二章:关系数据库知识 [数据库原理及应用]经典题库附答案(14章全)--第 ...

  5. 【数据库原理及应用】经典题库附答案(14章全)——第九章:数据库安全性

    [数据库原理及应用]经典题库附答案(14章全)--第一章:数据库基础知识 [数据库原理及应用]经典题库附答案(14章全)--第二章:关系数据库知识 [数据库原理及应用]经典题库附答案(14章全)--第 ...

  6. 【数据库原理及应用】经典题库附答案(14章全)——第八章:数据库并发控制

    [数据库原理及应用]经典题库附答案(14章全)--第一章:数据库基础知识 [数据库原理及应用]经典题库附答案(14章全)--第二章:关系数据库知识 [数据库原理及应用]经典题库附答案(14章全)--第 ...

  7. 【数据库原理及应用】经典题库附答案(14章全)——第七章:数据库恢复技术

    [数据库原理及应用]经典题库附答案(14章全)--第一章:数据库基础知识 [数据库原理及应用]经典题库附答案(14章全)--第二章:关系数据库知识 [数据库原理及应用]经典题库附答案(14章全)--第 ...

  8. 【数据库原理及应用】经典题库附答案(14章全)——第六章:关系数据库设计过程

    [数据库原理及应用]经典题库附答案(14章全)--第一章:数据库基础知识 [数据库原理及应用]经典题库附答案(14章全)--第二章:关系数据库知识 [数据库原理及应用]经典题库附答案(14章全)--第 ...

  9. 【数据库原理及应用】经典题库附答案(14章全)——第五章:关系数据理论

    [数据库原理及应用]经典题库附答案(14章全)--第一章:数据库基础知识 [数据库原理及应用]经典题库附答案(14章全)--第二章:关系数据库知识 [数据库原理及应用]经典题库附答案(14章全)--第 ...

最新文章

  1. 快速排序(快排)--->注释超详细
  2. Task.Run vs Task.Factory.StartNew
  3. 原理竟然是这!2021年字节跳动74道高级程序员面试
  4. 【小白学习C++ 教程】十三、C++命名空间namespace
  5. 程序员 sql面试_非程序员SQL使用指南
  6. 多态计算器的开发 c# 1614095334
  7. python写一个完整的小程序_写一个python小程序
  8. CSS3最颠覆性的动画效果,基本属性[过渡和2D]
  9. 推荐几本lisp的书.
  10. 阶段3 1.Mybatis_01.Mybatis课程介绍及环境搭建_07.环境搭建的注意事项
  11. python报错 unexpected keyword argument ‘categories‘
  12. ICRA 2020轨迹预测竞赛冠军的方法总结
  13. 计算机简单的办公操作,电脑操作掌握这15种快捷键技巧,你就是办公高手!
  14. 电信大数据治理与质量管理
  15. 用docker安装tomcat并实现目录映射端口映射输入ip地址测试网页连接
  16. 也许通过社群找工作,是未来的趋势。
  17. OpenCV目标追踪
  18. ctf MISC writeup
  19. java相对路径上上级_关于上级目录与上上级目录的表示相对路径
  20. 微信信息处理 微信公众平台开发教程(1)

热门文章

  1. 持续集成:部署发布篇
  2. Java集合—HashMap为什么2倍扩容
  3. mysql索引实现原理
  4. 《人月神话》---1
  5. 《微服务设计》(三)---- 集成
  6. 钟国晨160809323 (作业9)
  7. bzoj2005: [Noi2010]能量采集
  8. 5、shader混合(Blending)、雾
  9. 第4代白盒測试方法介绍--理论篇
  10. HAOI2018 染色