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 ...
随机推荐
- JS创建对象的方式有几种
相信但凡作为一个前端工程师,都被面试到过这个面试题目,HR考察的就是对oop思想的理解. 作为一个从后端转过来的怂逼,oop一直是心中的永远的痛啊. 这几天一直在通读js高级程序设计,重复理解js创建 ...
- [分享]在ubuntu9.10下实现开机自动登录并运行自己的图形程序
在ubuntu9.10下实现开机自动登录并运行自己的图形界面程序(本人接触ubuntu时日不长,文中一些说法难免有错误和疏漏之处,还请大家不吝批评指正.)实现步骤分以下三大步:1. 实现ubuntu文 ...
- JSP Response Set Status
JSP Response Set Status In this tutorial you will learn about how to set the HTTP status code in JSP ...
- 【Hadoop】HIVE 数据表 使用
3 使用 3.1 数据导入 3.1.1 可以使用命令行导入,也可以直接上传到HDFS的特定目录 3.1.2 格式问题 3.1.2.1 缺失/不合法字段默认值为NULL 3.1.2.2 最好数据是格式化 ...
- ECShop后台管理菜单修改
ECShop中,和后台菜单相关的文件有两个: ·菜单项:admin\includes\inc_menu.php·菜单文本:languages\zh_cn\admin\common.php 所以,要修改 ...
- 倍福TwinCAT(贝福Beckhoff)基础教程2.1 TwinCAT常见类型简介
常见数据类型可以参考EXCEL表格的内容,在准备值中输入非法数据,然后回车会有错误提示(例如BYTE数据输入256) 右击可以切换二进制或十进制显示,wData5可以被挨个采集每个位上的数据,也可 ...
- vue笔记四
十一.过渡与动画 1.使用限制Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加 entering/leaving 过渡条件渲染 (使用 v-if)条件展示 (使 ...
- Python学习笔记(一)类和继承的使用
一年前就打算学Python了,折腾来折腾去也一直没有用熟练,主要是类那一块不熟,昨天用Python写了几个网络编程的示例,感觉一下子迈进了很多.这几天把学习Python的笔记整理一下,内容尽量简洁. ...
- jquery文件上传控件 Uploadify(转)
原文:http://www.cnblogs.com/mofish/archive/2012/11/30/2796698.html 基于jquery的文件上传控件,支持ajax无刷新上传,多个文件同时上 ...
- 事务(Transaction)概念和特性
http://baike.baidu.com/view/121511.htm 概念 事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit).事务通常由高级数据库 ...