hash_map
点开一道第是自己oj的第440大关,想a了,一直想却无果,学长一句点醒,开始写hash。
关于这道题呢很无语了,两天卡在这上面,而且有些dalao不到20min就a了。我太菜了。
所以要深入讨论这道题啊,这时oj上的hash最后一题了,仔细总结!
首先我们发现求出前缀和后有一个n^2暴力枚举的做法可这道题n<=100000,很明显这是要我们搞出来一个nlog(n)的做法才行。
考虑优化,首先我们差分一下就很明显的发现我们可以在没次枚举到当前情况的时候和上一次的情况联系起来。
如果当前差分结果和上次(不知道是哪次)出现的结果一致,那么,就可以更新答案了。
不懂的话可以自己做一个关于样例的前缀和差分数组,一看就出来了。
那么当前情况拿什么来保存。数字太大了我们可以hash一下。(或者map
这就有了我82分代码:
//#include<bits/stdc++.h>
#include<iomanip>
#include<utility>
#include<cctype>
#include<vector>
#include<deque>
#include<map>
#include<stack>
#include<queue>
#include<bitset>
#include<set>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cstring>
#include<string>
#define INF 2147483646
#define mod 100007
using namespace std;
inline long long read()
{
long long x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void put(long long x)
{
x<?x=-x,putchar('-'):;
long long num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
const long long MAXN=;
long long a[MAXN];
long long lin[MAXN],nex[MAXN],ver[MAXN],e[MAXN],len=;
long long n,k,ans=;
long long b[MAXN][];
void hash(long long h,long long x,long long y)
{
ver[++len]=h;
nex[len]=lin[x];
lin[x]=len;
e[len]=y;
}
long long find(long long xx)
{
long long x=xx%mod;
if(lin[x]==)return -;
for(long long i=lin[x];i;i=nex[i])if(e[i]==xx)return ver[i];
return -;
}
void transform(long long h,long long x)
{
long long u=,minn=MAXN;
for(long long u=;u<=k;u++)
{
if(x&)b[h][u]=b[h-][u]+;
else b[h][u]=b[h-][u];
minn=min(b[h][u],minn);
x=x>>;
}
for(long long i=;i<=k;i++)
b[h][i]-=minn;
long long cnt=;
for(long long i=,t=;i<=k;i++,t=t*)cnt+=b[h][i]*t;
long long w=find(cnt);
if(w==-)hash(h,cnt%mod,cnt);
else ans=max(ans,h-w);
//cout<<cnt<<endl;
return; }
int main()
{
//freopen("1.in","r",stdin);
n=read();k=read();
hash(,,);
for(long long i=;i<=n;i++)
{
a[i]=read();
transform(i,a[i]);
}
put(ans);
return ;
}
很棒的代码对不对,但是只有82分,经过2h的打表发现就算采用挂链法也会导致明明不同的元素访问到。如 0(12)1这三个二进制数=25 而5(0)5=25;不一样但是hash后值是一样的。
则么办hash之后更加精细的判断即可。这样复杂度会很高。
//#include<bits/stdc++.h>
#include<iomanip>
#include<utility>
#include<cctype>
#include<vector>
#include<deque>
#include<map>
#include<stack>
#include<queue>
#include<bitset>
#include<set>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cstring>
#include<string>
using namespace std;
inline long long read()
{
long long x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void put(long long x)
{
x<?x=-x,putchar('-'):;
long long num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
const long long MAXN=;
const long long INF=;
const long long mod=;
vector<long long>q[MAXN];
long long a[MAXN];
long long lin[MAXN],nex[MAXN],ver[MAXN],e[MAXN],len=;
long long n,k,ans=;
long long b[MAXN][];
void hash(long long h,long long x,long long y,long long c[])
{
ver[++len]=h;
nex[len]=lin[x];
lin[x]=len;
e[len]=y;
for(long long i=;i<=k;++i)q[len].push_back(c[i]);
}
long long find(long long xx,long long c[])
{
long long x=xx%mod;
if(lin[x]==)return -;
for(long long i=lin[x];i;i=nex[i])
{
if(e[i]==xx)
{
bool flag=;
for(long long j=;j<=k;++j)if(c[j]!=q[i][j-]){flag=;break;}
if(flag==)return ver[i];
}
}
return -;
}
void transform(long long h,long long x)
{
long long u=,minn=INF;
for(long long u=;u<=k;++u)
{
if(x&)b[h][u]=b[h-][u]+;
else b[h][u]=b[h-][u];
minn=min(b[h][u],minn);
x=x>>;
}
for(long long i=;i<=k;++i)b[h][i]-=minn;
long long cnt=;
for(long long i=,t=;i<=k;++i,t=t<<)cnt+=b[h][i]*t;
long long w=find(cnt,b[h]);
if(w==-)hash(h,cnt%mod,cnt,b[h]);
else ans=max(ans,h-w);
return; }
int main()
{
//freopen("1.in","r",stdin);
n=read();k=read();
hash(,,,b[]);
for(long long i=;i<=n;++i)
{
a[i]=read();
transform(i,a[i]);
}
put(ans);
return ;
}
这个代码绝对很完美了,但是洛谷是可以通过的但是呢,oj上会超时的。
那么这个hash过于复杂,则么办呢。
我们可以使用map。映射直接映射到map上就会省很多的操作。
//#include<bits/stdc++.h>
#include<iomanip>
#include<utility>
#include<cctype>
#include<vector>
#include<deque>
#include<map>
#include<stack>
#include<queue>
#include<bitset>
#include<set>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cstring>
#include<string>
#define INF 2147483646
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
int x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
inline void put(int x)
{
x<?x=-x,putchar('-'):;
int num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
const int MAXN=;
int n,k,ans=;
int a[MAXN];
struct wy//闻道玉门犹被遮应将性命逐轻车
{
int h;
int c[];
}t[MAXN];
map<string,int>f;
string w;
int main()
{
//freopen("1.in","r",stdin);
n=read();k=read();
for(int i=;i<=n;i++)
{
w="";int flag=;
a[i]=read();int minn=INF;
t[i].h=i;int x=a[i];
for(int j=;j<=k;j++)
{
t[i].c[j]+=t[i-].c[j];
if(x&)t[i].c[j]+=;
x=x>>;minn=min(minn,t[i].c[j]);
}
for(int j=;j<=k;j++){t[i].c[j]-=minn,w+=t[i].c[j]+'';if(t[i].c[j]!=)flag=;}
int sum=f[w];
if(flag==)ans=max(ans,i);
if(sum)ans=max(ans,i-sum);
else f[w]=i;
}
put(ans);
return ;
}
这下复杂度再次大大下降。然后oj也是可以顺利通过的,但是这里学长有一个使用了结构替友元函数的。
学习更多的东西,所以这里有一个友元函数的代码:
//#include<bits/stdc++.h>
#include<iomanip>
#include<utility>
#include<cctype>
#include<vector>
#include<deque>
#include<map>
#include<stack>
#include<queue>
#include<bitset>
#include<set>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cstring>
#include<string>
#define INF 2147483646
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
int x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
inline void put(int x)
{
x<?x=-x,putchar('-'):;
int num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
const int MAXN=;
int n,k,ans=;
int a[MAXN];
struct wy//闻道玉门犹被遮应将性命逐轻车
{
int h;
int c[];
friend bool operator <(wy x,wy y)
{
for(int i=;i<=k;i++)
if(x.c[i]!=y.c[i])return x.c[i]<y.c[i];
return ;
} }t[MAXN];
map<wy,int>f;
int main()
{
//freopen("1.in","r",stdin);
n=read();k=read();
f[t[]]=;
for(int i=;i<=n;i++)
{
a[i]=read();int minn=INF;
t[i].h=i;int x=a[i];
for(int j=;j<=k;j++)
{
t[i].c[j]+=t[i-].c[j];
if(x&)t[i].c[j]+=;
x=x>>;minn=min(minn,t[i].c[j]);
}
for(int j=;j<=k;j++)t[i].c[j]-=minn;
int sum=f[t[i]];
if(sum)ans=max(ans,i+-sum);
else f[t[i]]=i+;
}
put(ans);
return ;
}
这个代码和刚刚的差不多,但是是对结构体的升华操作要学!
提交到poj上 第一个AC代码 TLE 第二个 TLE 第三个 TLE 全部都阵亡了,不服,教学长的代码,然后A了。这wy大佬是真的强啊。
经过调查不管如何进行读入、输出、卡常的优化都是TLE,然后感觉是map第一个关键字的原因的问题,因为学长的是小hash和map的结合体。
所以这道题可以考虑抄一波学长的代码他的第一个关键字是long long 类型的,所以应该要快(我也真找不出什么原因了。
而且他的hash是好hash 比我的第一个hash好上不少。完全不带重复的所以这个代码也应该是可以优化我的代码的。
所以他的代码经过我的翻译如下:
//#include<bits/stdc++.h>
#include<iomanip>
#include<utility>
#include<cctype>
#include<vector>
#include<deque>
#include<map>
#include<stack>
#include<queue>
#include<bitset>
#include<set>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cstring>
#include<string>
#define ll long long
#define INF 2147483646
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
int x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
inline void put(int x)
{
x<?x=-x,putchar('-'):;
int num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
const int MAXN=,maxn=;
int n,k,ans=;
int a[MAXN][];
map<ll,int>f;
int find(int x)
{
ll sum=;
for(int i=;i<=k;i++)sum=sum*maxn+1ll*a[x][i];
if(f[sum]==&&sum!=)f[sum]=x;
return f[sum];
}
int main()
{
freopen("1.in","r",stdin);
n=read();k=read();
for(int i=;i<=n;++i)
{
int t=,x=read();
int minn=INF;
for(int j=;j<=k;j++)
{
a[i][j]=x&;a[i][j]+=a[i-][j];
x=x>>;
minn=min(minn,a[i][j]);
}
for(int j=;j<=k;j++)a[i][j]-=minn;
ans=max(ans,i-find(i));
}
put(ans);
return ;
}
很妙的hash和map的嵌套~!
刚好的map接数字较大的集合,这样就实现了快速查找。
不用map可就接不上了。总结:所以必须要用map来进行精度较高但是比结构图或者string快的东西。累了一天,了。
明天加油!ヾ(◍°∇°◍)ノ゙
hash_map的更多相关文章
- map,hash_map, hash_table, 红黑树 的原理和使用
在刷算法题的时候总是碰到好多题,号称可以用hash table来解题.然后就蒙圈了. 1.首先,map和hash_map的区别和使用: (1)map底层用红黑树实现,hash_map底层用hash_t ...
- hash_map的简洁实现
hash_map的简洁实现 hash_map是经常被使用的一种数据结构,而其实现方式也是多种多样.如果要求我们使用尽可能简单的方式实现hash_map,具体该如何做呢? 我们知道hash_map最 ...
- map vs hash_map
1. map, multimap, set, multiset g++ 中 map, multimap, set, multiset 由红黑树实现 map: bits/stl_map.h multim ...
- Map和hash_map
map和hash_map 今天在写拼流的程序时碰到一个问题,要根据流的四元组的结构信息映射到该流的数据.也就是我在网络数据包拼接的过程中,要根据包的地址和端口信息,对应到其对应的一个流的数据上去,把端 ...
- map,hash_map和unordered_map 实现比较
map介绍 Map是STL[1]的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处 ...
- hash_map map
什么时候需要用hash_map,什么时候需要用map? 总体来说,hash_map 查找速度会比map快,而且查找速度基本和数据数据量大小,属于常数级别;而map的查找速度是log(n)级别.并不一定 ...
- hash_map vs unordered_map vs map vs unordered_set
hash_map vs unordered_map 这两个的内部结构都是采用哈希表来实现.unordered_map在C++11的时候被引入标准库了,而hash_map没有,所以建议还是使用unord ...
- 学习hash_map从而了解如何写stl里面的hash函数和equal或者compare函数
---恢复内容开始--- 看到同事用unordered_map了所以找个帖子学习学习 http://blog.sina.com.cn/s/blog_4c98b9600100audq.html (一)为 ...
- STL中map与hash_map的比较
1. map : C++的STL中map是使用树来做查找算法; 时间复杂度:O(log2N) 2. hash_map : 使用hash表来排列配对,hash表是使用关键字来计算表位置; 时间复杂度:O ...
- STL之hash_set和hash_map
Contents 1 hash_set和hash_map的创建与遍历 2 hash_set和hash_map的查找 3 建议 一句话hash_set和hash_map:它们皆由Hashtable(St ...
随机推荐
- 图灵数学·统计学丛书.PDF(53本全)
图灵数学·统计学丛书01-概率论及其应用(第1卷·第3版)-[美]William.Feller-人民邮电出版社.pdf 图灵数学·统计学丛书01-金融数学:衍生产品定价引论-[英]M·巴克斯特& ...
- Asp.Net MVC EF查询部分字段
例如新闻表中有几十个字段,而我们只需要显示标题和时间2个字段 如果是再Controller中查询使用的话比较简单 public string ceshi() { dbEntities db = new ...
- java框架篇---hibernate主键生成策略
Hibernate主键生成策略 1.自动增长identity 适用于MySQL.DB2.MS SQL Server,采用数据库生成的主键,用于为long.short.int类型生成唯一标识 使用SQL ...
- [php] thinkphp基于Http类 下载文件
http://blog.csdn.net/u010081689/article/details/49360937
- JVM 内部原理(七)— Java 字节码基础之二
JVM 内部原理(七)- Java 字节码基础之二 介绍 版本:Java SE 7 为什么需要了解 Java 字节码? 无论你是一名 Java 开发者.架构师.CxO 还是智能手机的普通用户,Java ...
- Sass编译时Invalid US-ASCII character解决办法
编译scss文件时,如果出现如下错误 Error: Invalid US-ASCII character "\xC2" on line 63 of src/assets/_scss ...
- Mac vim“装逼”配置
配置c++ 等编程语言补全等 from blog http://www.cnblogs.com/xiaobo-Linux/p/8909402.html 1. 安装 macvim brew instal ...
- 【Mac brew】代理安装brew insall
http_proxy=dev-proxy.**.**:8080 https_proxy=dev-proxy.**.**:8080 brew install npm
- oracle 学习笔记(2)创建表空间及用户授权
原文:http://www.cnblogs.com/smartvessel/archive/2009/07/06/1517690.html Oracle安装完后,其中有一个缺省的数据库,除了这个缺省的 ...
- ASP.NET MVC 4 (十三) 基于表单的身份验证
在前面的章节中我们知道可以在MVC应用程序中使用[Authorize]特性来限制用户对某些网址(控制器/控制器方法)的访问,但这都是在对用户认证之后,而用户的认证则依然是使用ASP.NET平台的认证机 ...