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 ...
随机推荐
- net.sf.json.JSONException: There is a cycle in the hierarchy!错误解决方案
net.sf.json.JSONException: There is a cycle in the hierarchy!错误解决方案 今天在用List集合转换成json数组的时候发生了这个错误,这个 ...
- python下性能提示
性能提示 3.1 嵌套if/else结构比一系列单选if结构块,因为只要有一个条件满足,其余测试就会终止. 3.2 在嵌套if/else结构中,把最可能成立的条件放在该嵌套结构的开始处.和把不常见的条 ...
- 【iOS开发-55】图片轮播案例:scrollView的分页、滚动栏、利用代理控制定时器和Page Control以及多线程问题
案例: (1)用storyboard布局,这里用了三样东西. --UIScrollView就是我们准备存放滚动图片的容器. --Page Control就是控制页数的那几个小点点.能够设置有多少个点. ...
- domino数据同步到sql server
近期有个需求,要同步domino数据到selservlet数据库,查看几年前ls使用odbc写的同步功能,还能正常使用.而且加入读者域进去功能(之前没有这个需求).改进成网页配置版本号(曾 ...
- jQuery的DOM操作之加入元素和删除元素
加入元素: .append()--在目标元素之后加入元素. .prepend()--在目标元素之前加入元素. .after()--在目标元素之后换行加入元素: .before()--在目标元素之前加入 ...
- iOS OC08,09_内存管理
//管理内存有三种方式, //1.是垃圾回收,java常见的管理内存的方法,系统来检測对象是否被使用,是否被释放 //2.MRC手动管理引用计数,iOS管理内存的方式,程序猿通过手动的方式来管理对象是 ...
- 从程序员到asp.net架构师转变[转]
微软的DotNet开发绝对是属于那种入门容易提高难的技术.而要能够成为DotNet架构师没有三年或更长时间的编码积累基本上是不可能的.特别是在大型软件项目中,架构师是项目核心成员,承上启下,因此 RU ...
- 可移动磁盘显示0kb打不开怎么办
移动硬盘.U盘打不开怎么办 为了方便共享,大多数人都购买了移动硬盘.那么如果有一天,发现移动硬盘打不开了,怎么办?下面为大家介绍移动硬盘打不开的解决方法. 未格式化故障 第一步:双击盘符出现未格式 ...
- BZOJ 1012 线段树||单调队列
非常裸的线段树 || 单调队列: 假设一个节点在队列中既没有时间优势(早点入队)也没有值优势(值更大),那么显然不管在如何的情况下都不会被选为最大值. 既然它仅仅在末尾选.那么自然能够满足以上的条件 ...
- poj 1079 Calendar Game(博弈论 SG)
Calendar Game Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) To ...