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 ...
随机推荐
- JAVA之抽象类与抽象方法
抽象方法:在类中没有方法体的方法,就是抽象方法.抽象类:含有抽象方法的类就叫抽象类.|||||||||抽象类不能被实例化(new)为什么要使用抽象方法?(以下是个人观点)因 为在面向对象的编程的思想中 ...
- python核心编程学习记录之Web编程
cgi未完待续
- thrift.transport.TTransport.TTransportException: Could not start SASL: Error in sasl_client_start (-4) SASL(-4): no mechanism available: No worthy mechs found
thrift.transport.TTransport.TTransportException: Could not start SASL: Error in sasl_client_start (- ...
- Spark map-side-join 关联优化
在spark中要进行join操作,如果在shuffle的时候进行join效率较低.如果满足 所需要join的表中有一张表较小,那么可以考虑在map端进行join操作. 转载:http://blog.c ...
- 联想T470设置U盘启动
联想T470设置U盘启动 学习了:http://www.udaxia.com/upqd/10092.html # F12 in Enter in USB HDD 如果不行: App Menu > ...
- DevExpress控件之GridControl、GridView
GridControl对应标准WinForm里的GridView,相当于是一个控件,里面包含多个GridView也可以放其它的控件 禁止修改gridView1.OptionsBehavior.Edit ...
- Node.js 使用angularjs取得Nodejs http服务端返回的JSON数组示例
server.js代码: // 内置http模块,提供了http服务器和客户端功能(path模块也是内置模块,而mime是附加模块) var http=require("http" ...
- 【读书笔记】【深入理解ES6】#1-块级作用域绑定
var声明及变量提升(Hoisting)机制 在函数作用域或全局作用域中通过var关键字声明的变量,无论实际上是在哪里声明的,都会被当成在当前作用域顶部声明的变量.这就是我们常说的提升(Hoistin ...
- java web中 classpath路径 详解
在使用ssh等框架开发web程序时配置文件(xml和properties)存放的路径一般为src下,当部署程序时则必须存在于classes路径下,具体如下 src不是classpath, WEB-IN ...
- 常用的二种修改mysql最大连接数的方法
方法一:进入MYSQL安装目录 打开MYSQL配置文件 my.ini 或 my.cnf查找 max_connections=100 修改为 max_connections=1000 服务里重起MY ...