理解就是,对于一些给定的东西,进行加密然后存入数组通常的加密一般是,转进制,比如说a-z这么二十六个字母,显然你可以将其转成数字之后再乘26每次,但是可能会有所超出限制比如说3823849534952342545353这么一串数字你明显保存不下来,怎么办呢,那么mod就可以排上用场,mod一个998244353就很不错。哦记住一下要模一个质数。
大佬发言: 所以我们主要处理“Hash函数”和“冲突情况”
- 一般Hash函数的构造需要一个mod数,通常定义为 不大于
n的最大素数 ,这样随机数据可以均匀的映射在构建的链表里。 - 同一个链中可能出现多个数,有一种“开散列”的解决案
是,将原始值映射后值相同的归为一类,构成一个链,接在表头
(映射值)之后,每条链的节点可以保存一些数据(我这道题就
是利用开散列),之后依次遍历即可,因为依赖于Hash函数,构
造的越好越接近O(1)
做一题hash:P1955 [NOI2015] 程序自动分析就是hash加并查集加一些优化,其实这个用的是hash表,具体就像链式前向星一样,用last与now来维护具体:
int in(int x)//我重点讲一下这一段,不妨考虑两种种情况:
//讨论两种,若之前有,返回之前的,若之前没有,新开一个
//感觉有更好的写法 呃大概没有了
{
int v=x%mod;
for(int i=last[v];i;i=h[i])
{
if(to[i]==x) return i;
}
h[++tot]=last[v],to[tot]=x,last[v]=tot;
return tot;
}
查询就和查询操作一样,就这样:
#include<bits/stdc++.h>
using namespace std;
int n,m,tot=0,tp=0,wb=0;
int to[2000001],fa[2000001],h[2000001],last[2000001];
int a[2000001],mod=1111111;
int xx[2000001],yy[2000001];//st[100001];
int findfa(int x)
{
if(fa[x]==x) return x;
return fa[x]=findfa(fa[x]);
}
int in(int x)//我重点讲一下这一段,不妨考虑两种种情况:
//讨论两种,若之前有,返回之前的,若之前没有,新开一个
//感觉有更好的写法 呃大概没有了
{
int v=x%mod;
for(int i=last[v];i;i=h[i])
{
if(to[i]==x) return i;
}
h[++tot]=last[v],to[tot]=x,last[v]=tot;
return tot;
}
int asknum(int x)
{
int v=x%mod;
for(int i=last[v];i;i=h[i])
{
if(to[i]==x) return i;
}
return 0;
}
void clean()
{
for(int i=1;i<=1000001;i++) fa[i]=i;
memset(h,0,sizeof(h));memset(last,0,sizeof(last));
tot=0;wb=0;
return ;
}
int main()
{
int t;scanf("%d",&t);
while(t--)
{
int pd=1;clean();
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x,y,p;scanf("%d%d%d",&x,&y,&p);
if(p==1)
{
x=in(x);y=in(y);//printf("*%d %d\n",x,y);
int fx=findfa(x),fy=findfa(y);
if(fx!=fy) fa[fx]=fy;
}
else xx[++wb]=x,yy[wb]=y;
}
for(int i=1;i<=wb;i++)
{
if(xx[i]==yy[i])
{
printf("NO\n");
pd=-1;break;
}
int x=asknum(xx[i]),y=asknum(yy[i]);//printf("*%d %d\n",x,y);
if(x&&y&&findfa(x)==findfa(y))
{
printf("NO\n");
pd=-1;break;
}
}
if(pd==1) printf("YES\n");
// for(int i=1;i<=n;i++) printf("%d ",findfa(i));
}
return 0;
}
下一个P1381 单词背诵小水题用string+map维护就行:
#include<bits/stdc++.h>
using namespace std;
map<string ,int >sum;
map<string ,bool > v;
int n,m,ans1=0,ans2=1e9;
string s[200001],sl;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) cin>>sl,v[sl]=1;
scanf("%d",&m);int l=1;
for(int i=1;i<=m;i++)
{
cin>>s[i];
if(v[s[i]]) sum[s[i]]++;
if(sum[s[i]]==1) ans1++,ans2=i-l+1;
while(l<=i)
{
if(!v[s[l]])
{
l++;
continue;
}
if(sum[s[l]]>=2)
{
sum[s[l]]--;
l++;
continue ;
}
break;
}
ans2=min(ans2,i-l+1);
}
printf("%d\n%d",ans1,ans2);
return 0;
}
下一个是一个可以不用hash的题目P4398 [JSOI2008]Blue Mary的战役地图所以就没做了(其实做了不过用dp QWQ),P3879 [TJOI2010] 阅读理解评蓝属实不太合理,不难看起来,呃属实是set万岁,学了一下set,用于判断set中有无这个数用count(x)有返回true,无返回false。
//学习新姿势,用set进行维护会好很多,哦最好使用双哈希
#include<bits/stdc++.h>
using namespace std;
int n,m,mod1=9982245353,mod2=11111111;
char a[1000001];
set<int> hs1[1000001],hs2[1000001];
void gethash(char s[],int len,int &k1,int &k2)
{
for(int i=1;i<=len;i++) k1=(k1*111+s[i])%mod1;
for(int i=1;i<=len;i++) k2=(k2*111+s[i])%mod2;
return ;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x,len,k1=0,k2=0;scanf("%d",&x);
while(x--)
{
scanf("%s",a+1);len=strlen(a+1);k1=0,k2=0;
gethash(a,len,k1,k2);hs1[i].insert(k1);hs2[i].insert(k2);
}
}
scanf("%d",&m);
while(m--)
{
int len,k1=0,k2=0;scanf("%s",a+1);
len=strlen(a+1);gethash(a,len,k1,k2);
for(int i=1;i<=n;i++)
{
if(hs1[i].count(k1)==true&&hs2[i].count(k2)==true) printf("%d ",i);
}
printf("\n");
}
return 0;
}
来个有趣些的,P5043 【模板】树同构([BJOI2015]树的同构)看一下第一个大佬的文章:https://www.luogu.com.cn/problem/solution/P5043,我们对于树同构应该先计算出重心,可能有一两个,记录下来,求重心的方式也较为巧妙,采用多项式hash(?)的方法,具体说:指的是,算了有点麻烦,我们采用另一种呃也是不知道什么hash:(学到了,我们下次把hash打乱~)
#include<bits/stdc++.h>
#define int long long
using namespace std;
int ans[10001][1001];
int len=0,last[1000001];
int n,m,mod=998244353,power=11111;
struct pp
{
int x,y,next;
};pp p[1000001];
void ins(int x,int y)
{
int now=++len;
p[now]={x,y,last[x]};last[x]=now;
return ;
}
bool cmp(const int &x,const int &y)
{
return x<y;
}
int gethash(int x,int fa)
{
int q[1001],ans=0,tot=0;
for(int i=last[x];i!=-1;i=p[i].next)
{
int y=p[i].y;if(y==fa) continue ;
q[++tot]=gethash(y,x);
}
sort(q+1,q+tot+1,cmp);
for(int i=1;i<=tot;i++) ans=(ans*power+q[i])%mod;
return (ans*power)%mod+1101;
}
signed main()
{
scanf("%lld",&m);
for(int i=1;i<=m;i++)
{
memset(last,-1,sizeof(last));len=0;
scanf("%lld",&n);
for(int j=1;j<=n;j++)
{
int x;scanf("%lld",&x);
if(x!=0) ins(j,x),ins(x,j);
}
for(int j=1;j<=n;j++) ans[i][j]=gethash(j,0);
sort(ans[i]+1,ans[i]+n+1,cmp);
for(int j=1;j<=i;j++)
{
int k=0;
while(k<=n)
{
if(ans[i][++k]!=ans[j][k]) break;
}
if(k>n)
{
printf("%lld\n",j);
break;
}
}
}
return 0;
}