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[],key=,Key[],pre[],ne[];
char ch[];
int n,m,pd[],sign;
int find(unsigned long long k){
int l=,r=n+;
while (l<r){
int mid=l+r>>;
if (x[mid]==k){
if (pd[mid]!=sign){
pd[mid]=sign; return ;
} else return ;
}
if (x[mid]>k) r=mid; else l=mid+;
}
return ;
}
int main(){
scanf("%d%d",&n,&m);
for (int i=;i<=n;i++){
scanf("%s",ch+); int len=strlen(ch+);
for (int j=;j<=len;j++) x[i]=x[i]*key+ch[j];
}
Key[]=;
for (int i=;i<=;i++) Key[i]=Key[i-]*key;
sort(x+,x+n+);
for (;m;m--){
scanf("%s",ch+); int len=strlen(ch+); int ans=; sign++;
for (int j=;j<=len;j++) pre[j]=pre[j-]*key+ch[j];
ne[len+]=;
for (int j=len;j;j--) ne[j]=ne[j+]+ch[j]*Key[len-j];
for (int i=;i<=len;i++)
for (int j='a';j<='z';j++){
unsigned long long now=pre[i]*Key[len-i+]+j*Key[len-i]+ne[i+];
ans+=find(now);
}
printf("%d\n",ans);
}
return ;
}
再附上我的又乱又长的代码:
//
// 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[];
char str[];
unsigned long long g[];
int n,m; int tsave[];
int tcnt;
int tmark[]; map<unsigned long long,int> mhash;
set<unsigned long long> mark; int myfind(unsigned long long x)
{
//找到x在myhash中出现的次数
int b=,d=n;
while(b<d)
{
int mid=(b+d)/;
if( x <= myhash[mid] )
d = mid;
else b = mid+;
}
if(myhash[b]!=x || tmark[b]==) return ; tmark[b]=;
tsave[ tcnt++ ]=b; return ; int tb=b;
b=,d=n;
while(b<d)
{
int mid=(b+d+)/;
if( x >= myhash[mid] )
b = mid;
else d= mid-;
}
return b-tb+;
} int main() { scanf("%d%d",&n,&m); //mhash.clear();
for(int i=;i<=n;i++)
{
scanf("%s",str);
unsigned long len=strlen(str);
unsigned long long tmp=;
unsigned long long sum=; for(int j=;j<len;j++)
{
sum += tmp*(str[j]-'a'+);
tmp = tmp*K;
}
//mhash[sum]++;
myhash[ i ] = sum;
} sort(myhash+,myhash+n+);
memset(tmark,,sizeof(tmark)); for(int i=;i<m;i++)
{
//mark.clear();
tcnt=; scanf("%s",str);
int len=strlen(str); unsigned long long tmp=;
for(int j=;j<len;j++)
{
g[j] = tmp*(str[j]-'a'+);
tmp = tmp*K;
} for(int j=len-;j>=;j--)
{
g[j] += g[j+];
}
g[len]=; int ans=;
tmp = ;
unsigned long long nw=; for(int j=-;j<len;j++)
{
for(int p=;p<=;p++)
{
unsigned long long tt=nw+p*tmp+g[j+]*K; if(myfind(tt)==)
{
ans++;
} } nw += tmp*(str[j+]-'a'+);
tmp *=K;
} for(int j=;j<tcnt;j++)
tmark[ tsave[j] ]=; printf("%d\n",ans);
}
return ;
}
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[];
vector<ull>t[]; //不需要二分,不需要排序。 struct HashNode
{
int next;
ull key;//防止冲突
int id;
}hashnode[]; int pre[ HASHN ],cnt;
int ansans[][][]; void hash_insert(ull key,int id)
{
int hashkey = key%HASHN;
int num=;
for(int p=pre[hashkey];p!=-;p = hashnode[p].next)
{
ull nkey = hashnode[p].key ;
int nid = hashnode[p].id ;
if( nkey == key )
{
if(id==nid) return ;
num++;
if(num>=) return ;//有三个了,直接返回.
}
}
//没有找到相同的,或者相同数目不超过三个,则插入
hashnode[cnt].key = key;
hashnode[cnt].id = id;
hashnode[cnt].next = pre[hashkey];
pre[ hashkey ] = cnt++;
} void update(int s[],int x)
{
if(x==s[]||x==s[]||x==s[]) return ;
if(x<s[])
{
s[]=s[];
s[]=s[];
s[]=x;
}
else if(x<s[])
{
s[]=s[];
s[]=x;
}
else if(x<s[]) s[]=x;
} void myfind(ull x,int s[])
{
//找到x在myhash中出现的次数
int hashkey = x%HASHN;
for(int p=pre[hashkey];p!=-;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[];
unsigned long len; for(int i=;i<n;i++)
{
scanf("%s",str);
len=strlen(str);
for(int j=;j<len;j++)
s[i].push_back(str[j]-'a'+);
}
for(int i=;i<m;i++)
{
scanf("%s",str);
unsigned long len=strlen(str);
for(int j=;j<len;j++)
t[i].push_back(str[j]-'a'+);
} //第一个问题。t添加两个字母,等价于s删除一个,t添加一个
//第一步,将s进行hash
cnt=;
memset(pre,-,sizeof(pre));
ull savetmp[];
for(int i=;i<n;i++)
{
len = s[i].size();
ull tmp=;
for(int j=;j<len;j++)
{
savetmp[j] = tmp*s[i][j];
tmp *= K;
}
savetmp[len] = ;
for(int j=len-;j>=;j--)
savetmp[j] += savetmp[j+];
tmp=;
ull sum=;
for(int j=;j<len;j++)//删除第j个点
{
hash_insert(sum+savetmp[j+],i);
sum += s[i][j]*tmp;
tmp *= K;
}
} int ans[];
/*
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=;i<m;i++)
{
len = t[i].size();
ull tmp=K;
for(int j=;j<len;j++)
{
savetmp[j] = tmp*t[i][j];
tmp *= K;
}
savetmp[len] = ;
for(int j=len-;j>=;j--)
savetmp[j] += savetmp[j+]; ans[]=ans[]=ans[]=INF;
ull sum=;
tmp=;
for(int j=;j<=len;j++)
{
for(int k=;k<=;k++)
{
myfind(sum+k*tmp+savetmp[j],ans);
}
sum += tmp*t[i][j];
tmp *= K;
} for(int j=;j<;j++)
{
if(ans[j]!=INF) ansans[i][][j]=ans[j]+;
else ansans[i][][j]=-;
}
//printf("\n");
} //修改两个的时候。
cnt=;
memset(pre,-,sizeof(pre)); for(int i=;i<n;i++)
{
len = s[i].size();
ull tmp=K;
for(int j=;j<len;j++)
{
savetmp[j] = tmp*s[i][j];
tmp *= K;
}
savetmp[len] = ;
for(int j=len-;j>=;j--)
savetmp[j] += savetmp[j+];
tmp=;
ull sum=;
for(int j=;j<len;j++)//修改第j个点
{
for(int k=;k<=;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=;i<m;i++)
{
len = t[i].size();
ull tmp=;
for(int j=;j<len;j++)
{
savetmp[j] = tmp*t[i][j];
tmp *= K;
}
savetmp[len] = ;
for(int j=len-;j>=;j--)
savetmp[j] += savetmp[j+]; ans[]=ans[]=ans[]=INF;
ull sum=;
tmp=;
for(int j=;j<len;j++)
{
for(int k=;k<=;k++)
{
myfind(sum+k*tmp+savetmp[j+],ans);
}
sum += tmp*t[i][j];
tmp *= K;
} for(int j=;j<;j++)
{
if(ans[j]!=INF) ansans[i][][j]=ans[j]+;
else ansans[i][][j]=-;
}
} //删除两个
cnt=;
memset(pre,-,sizeof(pre)); for(int i=;i<n;i++)
{
len = s[i].size();
ull tmp=K;
for(int j=;j<len;j++)
{
savetmp[j] = tmp*s[i][j];
tmp *= K;
}
savetmp[len] = ;
for(int j=len-;j>=;j--)
savetmp[j] += savetmp[j+];
tmp=;
ull sum=;
for(int j=;j<=len;j++)//添加第j个点
{
for(int k=;k<=;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=;i<m;i++)
{
len = t[i].size();
ull tmp=;
for(int j=;j<len;j++)
{
savetmp[j] = tmp*t[i][j];
tmp *= K;
}
savetmp[len] = ;
for(int j=len-;j>=;j--)
savetmp[j] += savetmp[j+]; ans[]=ans[]=ans[]=INF;
ull sum=;
tmp=;
for(int j=;j<len;j++)
{
myfind(sum+savetmp[j+],ans); sum += tmp*t[i][j];
tmp *= K;
} for(int j=;j<;j++)
{
if(ans[j]!=INF) ansans[i][][j]=ans[j]+;
else ansans[i][][j]=-;
}
} for(int i=;i<m;i++)
for(int j=;j<;j++)
{
for(int k=;k<;k++)
printf("%d ",ansans[i][j][k]);
printf("\n");
}
return ;
}
hihocoder1260,1261 (HASH经典题)的更多相关文章
- poj 1611:The Suspects(并查集,经典题)
The Suspects Time Limit: 1000MS Memory Limit: 20000K Total Submissions: 21472 Accepted: 10393 De ...
- Hihicoder 题目1 : Trie树(字典树,经典题)
题目1 : Trie树 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编 ...
- poj 3264:Balanced Lineup(线段树,经典题)
Balanced Lineup Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 32820 Accepted: 15447 ...
- poj 2503:Babelfish(字典树,经典题,字典翻译)
Babelfish Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 30816 Accepted: 13283 Descr ...
- poj 2001:Shortest Prefixes(字典树,经典题,求最短唯一前缀)
Shortest Prefixes Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 12731 Accepted: 544 ...
- hdu 1247:Hat’s Words(字典树,经典题)
Hat’s Words Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- hdu 1075:What Are You Talking About(字典树,经典题,字典翻译)
What Are You Talking About Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 102400/204800 K ...
- hdu 1251:统计难题(字典树,经典题)
统计难题 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131070/65535 K (Java/Others)Total Submi ...
- poj 1006:Biorhythms(水题,经典题,中国剩余定理)
Biorhythms Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 110991 Accepted: 34541 Des ...
随机推荐
- 【OpenGL4.0】GLSL渲染语言入门与VBO、VAO使用:绘制一个三角形 【转】
http://blog.csdn.net/xiajun07061225/article/details/7628146 以前都是用Cg的,现在改用GLSL,又要重新学,不过两种语言很多都是相通的. 下 ...
- wp8开发时模拟器无法联网解决方法
关于模拟器无法联网的正常解决方案在网上有很多 这里讲的是我在做测试的时候模拟器无法上网的特殊情况 由于使用的是无线网络 可能有一些差别 过程如图: 启动模拟器 如果之前没有设置过模拟器的交换器则会出现 ...
- 转: 理解UDDI (from IBM Dev)
from: http://www.ibm.com/developerworks/cn/webservices/ws-featuddi/index.html 何为 UDDI? UDDI 项目鼓励 Web ...
- OC第五课
主要内容:字典.集合.数组排序 一.字典 演示样例: name : @" 张三 " .sex:@" 男 " ; age :@" 21 " ; ...
- 当php懈垢windows通用上传缺陷
转自独自等待博客 早上逛乌云发现了PKAV大牛的一篇文章,针对php和windows文件上传的分析,思路很YD,果断转之与大家分享. 虽然此文可能有许多的限制条件,但是如果你认真阅读会发现,其实还是比 ...
- golang一些知识点
2.冒泡排序(二维数组使用): func main() { i := 1 MYLABEL: for { i++ if i > 3 { break MYLABEL } } fmt.Println( ...
- vuex简单示例
一.vuex是什么,解决了什么问题? 官方解释是:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生 ...
- rabbitmq 用户和授权
官方文档 https://my.oschina.net/hncscwc/blog/262246?p=
- Git学习小结
版本控制工具 集中式: CVS SVN 集大成者 分布式:git 创始人:inux Towards 2005年 工具 最好使用linux(oh-my-zsh) gitbash -> cygwin ...
- 按“开始”-“运行”,或按WIN+R,在[运行]窗口中输入
command--------CMD命令提示符 ipconfig查看本机IP chkdsk.exe-----Chkdsk磁盘检查 certmgr.msc----证书管理实用程序 calc--- ...