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

  1. poj 1611:The Suspects(并查集,经典题)

    The Suspects Time Limit: 1000MS   Memory Limit: 20000K Total Submissions: 21472   Accepted: 10393 De ...

  2. Hihicoder 题目1 : Trie树(字典树,经典题)

    题目1 : Trie树 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编 ...

  3. poj 3264:Balanced Lineup(线段树,经典题)

    Balanced Lineup Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 32820   Accepted: 15447 ...

  4. poj 2503:Babelfish(字典树,经典题,字典翻译)

    Babelfish Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 30816   Accepted: 13283 Descr ...

  5. poj 2001:Shortest Prefixes(字典树,经典题,求最短唯一前缀)

    Shortest Prefixes Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 12731   Accepted: 544 ...

  6. hdu 1247:Hat’s Words(字典树,经典题)

    Hat’s Words Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total ...

  7. hdu 1075:What Are You Talking About(字典树,经典题,字典翻译)

    What Are You Talking About Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/204800 K ...

  8. hdu 1251:统计难题(字典树,经典题)

    统计难题 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131070/65535 K (Java/Others)Total Submi ...

  9. poj 1006:Biorhythms(水题,经典题,中国剩余定理)

    Biorhythms Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 110991   Accepted: 34541 Des ...

随机推荐

  1. JS创建对象的方式有几种

    相信但凡作为一个前端工程师,都被面试到过这个面试题目,HR考察的就是对oop思想的理解. 作为一个从后端转过来的怂逼,oop一直是心中的永远的痛啊. 这几天一直在通读js高级程序设计,重复理解js创建 ...

  2. [分享]在ubuntu9.10下实现开机自动登录并运行自己的图形程序

    在ubuntu9.10下实现开机自动登录并运行自己的图形界面程序(本人接触ubuntu时日不长,文中一些说法难免有错误和疏漏之处,还请大家不吝批评指正.)实现步骤分以下三大步:1. 实现ubuntu文 ...

  3. JSP Response Set Status

    JSP Response Set Status In this tutorial you will learn about how to set the HTTP status code in JSP ...

  4. 【Hadoop】HIVE 数据表 使用

    3 使用 3.1 数据导入 3.1.1 可以使用命令行导入,也可以直接上传到HDFS的特定目录 3.1.2 格式问题 3.1.2.1 缺失/不合法字段默认值为NULL 3.1.2.2 最好数据是格式化 ...

  5. ECShop后台管理菜单修改

    ECShop中,和后台菜单相关的文件有两个: ·菜单项:admin\includes\inc_menu.php·菜单文本:languages\zh_cn\admin\common.php 所以,要修改 ...

  6. 倍福TwinCAT(贝福Beckhoff)基础教程2.1 TwinCAT常见类型简介

    常见数据类型可以参考EXCEL表格的内容,在准备值中输入非法数据,然后回车会有错误提示(例如BYTE数据输入256)   右击可以切换二进制或十进制显示,wData5可以被挨个采集每个位上的数据,也可 ...

  7. vue笔记四

    十一.过渡与动画 1.使用限制Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加 entering/leaving 过渡条件渲染 (使用 v-if)条件展示 (使 ...

  8. Python学习笔记(一)类和继承的使用

    一年前就打算学Python了,折腾来折腾去也一直没有用熟练,主要是类那一块不熟,昨天用Python写了几个网络编程的示例,感觉一下子迈进了很多.这几天把学习Python的笔记整理一下,内容尽量简洁. ...

  9. jquery文件上传控件 Uploadify(转)

    原文:http://www.cnblogs.com/mofish/archive/2012/11/30/2796698.html 基于jquery的文件上传控件,支持ajax无刷新上传,多个文件同时上 ...

  10. 事务(Transaction)概念和特性

    http://baike.baidu.com/view/121511.htm 概念 事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit).事务通常由高级数据库 ...