点开一道第是自己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的更多相关文章

  1. map,hash_map, hash_table, 红黑树 的原理和使用

    在刷算法题的时候总是碰到好多题,号称可以用hash table来解题.然后就蒙圈了. 1.首先,map和hash_map的区别和使用: (1)map底层用红黑树实现,hash_map底层用hash_t ...

  2. hash_map的简洁实现

    hash_map的简洁实现   hash_map是经常被使用的一种数据结构,而其实现方式也是多种多样.如果要求我们使用尽可能简单的方式实现hash_map,具体该如何做呢? 我们知道hash_map最 ...

  3. map vs hash_map

    1. map, multimap, set, multiset g++ 中 map, multimap, set, multiset 由红黑树实现 map: bits/stl_map.h multim ...

  4. Map和hash_map

    map和hash_map 今天在写拼流的程序时碰到一个问题,要根据流的四元组的结构信息映射到该流的数据.也就是我在网络数据包拼接的过程中,要根据包的地址和端口信息,对应到其对应的一个流的数据上去,把端 ...

  5. map,hash_map和unordered_map 实现比较

    map介绍 Map是STL[1]的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处 ...

  6. hash_map map

    什么时候需要用hash_map,什么时候需要用map? 总体来说,hash_map 查找速度会比map快,而且查找速度基本和数据数据量大小,属于常数级别;而map的查找速度是log(n)级别.并不一定 ...

  7. hash_map vs unordered_map vs map vs unordered_set

    hash_map vs unordered_map 这两个的内部结构都是采用哈希表来实现.unordered_map在C++11的时候被引入标准库了,而hash_map没有,所以建议还是使用unord ...

  8. 学习hash_map从而了解如何写stl里面的hash函数和equal或者compare函数

    ---恢复内容开始--- 看到同事用unordered_map了所以找个帖子学习学习 http://blog.sina.com.cn/s/blog_4c98b9600100audq.html (一)为 ...

  9. STL中map与hash_map的比较

    1. map : C++的STL中map是使用树来做查找算法; 时间复杂度:O(log2N) 2. hash_map : 使用hash表来排列配对,hash表是使用关键字来计算表位置; 时间复杂度:O ...

  10. STL之hash_set和hash_map

    Contents 1 hash_set和hash_map的创建与遍历 2 hash_set和hash_map的查找 3 建议 一句话hash_set和hash_map:它们皆由Hashtable(St ...

随机推荐

  1. 当visual studio的数据库项目遇到SQL71501

    这是因为数据库项目缺少login用户. 加上就好了,注意要加sql server用户. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5 ...

  2. masscan

    masscan是一个快速的端口扫描工具 大概说一下它的使用方法,既有原创也有翻译 欢迎补充 扫描10.x.x.x的网络:masscan 10.0.0.0/8 -p80 程序将自动探测网络的接口和适配器 ...

  3. VMware 虚拟机安装OSX el capitan 11.12

    今天在虚拟机里装苹果OSX ,参考下文: http://wenku.baidu.com/link?url=eq6lxPfiGPcNbQiFiykJDgYDtdzG238P6_-T8IKxbKyDHX0 ...

  4. [Laravel] 08 - Auth & Data Migration

    登录注册框架 一.加载Auth模块 Step 1, 安装Auth模块 生成相关 laravel 框架内部的代码模块: $ php artisan make:auth 自动添加了路由代码 在larave ...

  5. mysql按月查询

    SELECT DATE_FORMAT(GenerateTime, '%m') as month, SUM(GenerateCount) AS count FROM identitycodetask ' ...

  6. NUC972 linux 烧录

    节介绍如何刻录uboot.kernel和文件系统到NAND Flash, 并且设定NUC970系列芯片从NAND Flash中开机.本节操作需要windows环境下进行.(初次连接电脑需要安装驱动) ...

  7. 为什么HTML使用<!DOCTYPE HTML>

    不管是刚接触前端,还是你已经“精通”web前端开发的内容,你应该知道在你写html的时候需要定义文档类型:你知道如果没有它,浏览器在渲染页面的时候会使用怪异模式:你知道各个浏览器在怪异模式下对各个元素 ...

  8. java基本数据结构和算法

    private class Node {  6 private Object data; //数据 7 private Node next = null; //指向下个结点的引用 8 9 public ...

  9. ORM跨表查询问题

    环境准备: 表结构 from django.db import models # Create your models here. class Publisher(models.Model): id ...

  10. get_or_create函数

    get_or_create函数比较好用. 如果查询到就返回,如果没查询到就向数据库加入新的对象. e.g. size = Size.objects.get_or_create(sizeName=siz ...