hash专题
来源:互联网 发布:野草教学设计软件 编辑:程序博客网 时间:2024/06/06 09:21
ural1486二维hash
http://acm.timus.ru/problem.aspx?space=1&num=1486
题意:
一个最大500*500的字符矩阵,求最大的两个相同的字符正方形。正方形可以有重叠部分但不能重合。
tip:
二分答案,二分查找正方形的边长,然后使用一个Hash表来判断该边长是否可行。Hash函数二维情况。时间复杂度是O(NMlog(N*M))的。检查是否产生了相同的Hash函数,如果存在相同的Hash函数,则认为该边长可行,否则即认为它不可行。
#include <cstdio>#include <iostream>#include <cstring>#include <map>using namespace std;typedef unsigned long long ui;typedef long long LL;const int maxn = 510;const ui MOD = 1e5+7;int n,m,ans,ans1x,ans2x,ans1y,ans2y;//n行m列LL cnt;char s[maxn][maxn];ui P = 233,Q= 23333,nc[maxn],mc[maxn],h[maxn][maxn];//P:列上的乘数,Q:行上的乘数void init(){ ans =0; nc[0] = 1;mc[0] = 1; for(int i = 1 ;i <= n ; i++){ nc[i] = nc[i-1] * P; //cout <<"nc"<<nc[i]<<endl; mc[i] = mc[i-1] * Q; } for(int i = 1 ;i <= n ; i++){ scanf("%s",s[i]+1); } for(int i = 1; i <= n ; i++){ //cout<<s[i]+1<<endl; for(int j = 1; j <= m ; j++){ h[i][j] = h[i][j-1]*Q+s[i][j]-'a'+1;//一行的 } } for(int i = 2; i <= n ; i++){ for(int j = 1; j <= m ; j++){ h[i][j] = h[i][j]+h[i-1][j]*P;//加上前面行的*列的乘数 } }// for(int i = 1; i <= n ; i++){// for(int j = 1; j <= m ; j++)// cout <<h[i][j]<<" ";// cout <<endl;// }}ui gethash(int x1,int x2,int y1,int y2,int mid){ ui tmp = h[x2][y2] - h[x1-1][y2]*nc[mid] - h[x2][y1-1]*mc[mid]; tmp += h[x1-1][y1-1]*nc[mid]*mc[mid]; return tmp;}struct node{ LL k; int x,y; ui data;}book[100010];bool check(int mid){ cnt++; for(int i = 1; i <= n-mid+1 ; i++){ for(int j = 1; j <= m-mid+1; j++){ ui _hash = gethash(i,i+mid-1,j,j+mid-1,mid);// if(mid == 3 && i == 1&& j == 1)// cout <<"hash1 = "<<_hash<<endl;// if(mid == 3&& i == 3 && j == 3)// cout<<"hash2 = "<<_hash<<endl; ui pos = _hash%MOD; if(book[pos].k == cnt&& book[pos].data == _hash){ if(mid > ans){ ans = mid; ans1x = book[pos].x; ans1y = book[pos].y; ans2x = i; ans2y = j; } return true; } book[pos].k=cnt;book[pos].x = i;book[pos].y = j;book[pos].data=_hash; } } return false;}void sov(){ int l = 1 ; int r = min(n,m); while(l <= r){ int mid = (l+r)/2; //cout <<"md = "<<mid<<endl; if(check(mid)){ l = mid+1; } else{ r = mid-1; } } if(ans1x > ans2x){ swap(ans1x,ans2x); swap(ans1y,ans2y); } if(ans) printf("%d\n%d %d\n%d %d\n",ans,ans1x,ans1y,ans2x,ans2y); else printf("0\n");}int main(){ while(~scanf("%d%d",&n,&m)){ init(); sov(); }}
vijos 有根树同构,图的hash
题意:
判断两个树同构
tip:
转换成判断两个图是否同构,对每个点的度数做hash,迭代(10层?),初始为每个点最开始的度,迭代时用上一次别的点迭代的结果(所有连边的点度数排个序)和这个点的迭代PQ不设成一个。
图的hash还可以距离啊什么
#include <iostream>#include <cstring>#include <algorithm>#include <cstdio>#include <map>using namespace std;const int maxn =110;typedef unsigned long long ui;int a,b,n,T,tot,head[maxn],TAT[maxn],sorthead[maxn],tot2,head2[maxn];ui d[maxn],tmp[maxn],so[maxn],ans[maxn];map<ui,int> mp;ui P = 1e9+7,Q = 1e9+9,X = 3214567;struct node{ int v,next;}edges[maxn],edges2[maxn];void add(int u,int v){ edges[tot].v = v;edges[tot].next = head[u];head[u] = tot++; edges[tot].v = u;edges[tot].next = head[v];head[v] = tot++;}void addt(int u,int v){ edges[tot].v = v;edges[tot].next = head[u];head[u] = tot++;}void add2(int u,int v){ edges2[tot2].v = v;edges2[tot2].next = head2[u];head2[u] = tot2++;}ui gethash(){ int cl = 10; while(cl--){ for(int i = 1; i <= n ; i++){ int cnt = 0; tmp[i] = 0; for(int k = head[i]; k != -1; k = edges[k].next){ so[cnt++] = d[edges[k].v]; } sort(so,so+cnt); for(int j = 0 ; j < cnt ;j++) tmp[i] = tmp[i]*P+so[j]; tmp[i] = tmp[i]+d[i]*Q; } for(int i = 1; i <= n ; i++){ d[i] = tmp[i]; } } sort(d+1,d+n+1); ui no = d[1]; for(int i = 2; i <= n ; i++) no = no*X+d[i]; return no;}void init(){ scanf("%d%d",&T,&n); for(int k = 1; k <= T ; k++){ tot= 0; for(int i = 0; i <= n; i++) d[i] = 0,head[i] = -1; for(int i = 1; i < n ; i++){ scanf("%d%d",&a,&b); d[a]++;d[b]++; add(a,b); } ans[k] = gethash(); //cout << ans[k]<<"we"<<endl; }}void sov(){ tot = 0; for(int i = 0 ; i <= T ;i++) head[i] = -1; for(int i = 1; i <= T ; i++){ if(mp[ans[i]]== 0) mp[ans[i]] = i; addt(mp[ans[i]],i); //cout << mp[ans[i]]<<" -."<<i<<endl; // cout <<"mp[ "<<ans[i]<<" ] = "<<mp[ans[i]]<<endl; } int cl = 0; for(int i = 0 ; i <= T ;i++) head2[i] = -1; tot2 = 0; for(int i = 1; i <= T ; i++){ if(mp[ans[i]] == i){ //cout <<" i = "<<i<<endl; for(int p = 0 ;p <= T ;p++) TAT[p] = 0; int num = 0; for(int k = head[i] ; k != -1; k = edges[k].next){ //cout << "i = "<<i <<" next = "<<edges[k].v<<endl; TAT[num++] = edges[k].v; } sort(TAT,TAT+num); sorthead[cl++] = TAT[0]; for(int k = num-1; k >= 1 ; k--) add2(TAT[0],TAT[k]); } } sort(sorthead,sorthead+cl); for(int i = 0 ; i < cl ; i++){ printf("%d",sorthead[i]); for(int k = head2[sorthead[i]] ; k != -1; k = edges2[k].next) printf("=%d",edges2[k].v); printf("\n"); }}int main(){ init(); sov();}
uva11996
题意:
题意:给定一个长度为n的01串,你的任务是依次执行如表所示的m条指令:
1 p c 在第p个字符后插入字符,p = 0表示在整个字符串之前插入
2 p 删除第p个字符,后面的字符往前移
3 p1 p2反转第p1到第p2个字符
4 p1 p2输出从p1开始和p2开始的两个后缀的LCP。
tip:
分块,根号(n+m)/2 ~根号(n+m)的长度,维护该块index,left块,right块,里面的字符串,字符串长度,正反hash值。
1.插入,从第一个块开始(首尾添加块0)算长度,找到属于的块,插入,若lenth>根号(n+m) ,把一个块分开,暴力后面块,前面可以直接球出来
若合格,O(lenth)的复杂度重新算hash
2.删除,若太小,则合并,合并两个块只需要O(1), 否则直接删除。。。删除时候O(lenth)
3.反转:若干整块加两边的小块,小块的地方直接暴力,求两个块新的hash值,中间部分直接反转,正反hash掉,然后left块,right块反过来O(lenth)
4.询问,二分当前lenth和,看这么长的字符串hash是否相同,O(1)求多个块合起来的hash 零碎部分暴力O(lenth*logn)
上述复杂度的lenth都是根号n的规模
以下引用论文:
如果两个串不会变化,求LCP只需要求出A+B的后缀数组即可。但是本题的A串是不断变化的,而且由变化的方式可以看出,每次操作都会导致后缀数组发生很大的变化,因此我们应该另辟蹊径。
对于一个k,不难判断两个串的LCP是否有至少k个字符:计算这两个串的前k个字符的Hash值,并且比较它们是否相等。如果相等,就几乎可以肯定地认为这两个串的LCP至少有k个字符,否则,它们的LCP长度肯定不到k。这样,就可以通过二分查找来计算LCP。
现在问题又转化成了怎么求一个子串的Hash。不妨仍然采用Rabin-Karp的Hash函数,如果已知了S1和S2的Hash值,不难求出S1+S2的Hash值:
而 的Hash值显然又是可以在O(n)时间 内预处理的得到的。因此,可以在O(1)时间内通过两个字符串的Hash值得到它们连接后得到的串的Hash值。因此,可以使用块状链表维护计算A中子串的Hash值,方法于维护计算部分和类似,不同之处在于一个字符串正向和反向的Hash值是不同的,为了能在O(n0.5)时间内完成reverse操作,应当要能在O(1)时间内把一个块“反转”,这就要求我们为一个块维护两个Hash值:一个是正向的,一个是倒向的。除此之外的操作于维护部分和或者维护最大值类似。这样,插入,删除,反转操作是O(n0.5)的,而查询操作是O(n0.5logn)的。
类似地,本题的另一种解法是在一棵splay树上维护Hash值。每次一个节点被旋转或以它为根的子树被修改时,则计算它的正向Hash值和反向Hash值,这样,就可以在O(1)时间你reverse一棵子树,通过split可以不难地把一棵子树在均摊O(logn)时间内反转。插入,删除操作显然也是均摊O(logn)的,而查询操作的均摊时间复杂度为O(log2n)
/*题意:给定一个长度为n的01串,你的任务是依次执行如表所示的m条指令:1 p c 在第p个字符后插入字符,p = 0表示在整个字符串之前插入2 p 删除第p个字符,后面的字符往前移3 p1 p2反转第p1到第p2个字符4 p1 p2输出从p1开始和p2开始的两个后缀的LCP。*//*分块,根号(n+m)/2 ~根号(n+m)的长度,维护该块index,left块,right块,里面的字符串,字符串长度,正反hash值。1.插入,从第一个块开始(首尾添加块0)算长度,找到属于的块,插入,若lenth>根号(n+m) ,把一个块分开,暴力后面块,前面可以直接球出来若合格,O(lenth)的复杂度重新算hash2.删除,若太小,则合并,合并两个块只需要O(1), 否则直接删除。。。删除时候O(lenth)3.反转:若干整块加两边的小块,小块的地方直接暴力,求两个块新的hash值,中间部分直接反转,正反hash掉,然后left块,right块反过来O(lenth)4.询问,二分当前lenth和,看这么长的字符串hash是否相同,O(1)求多个块合起来的hash 零碎部分暴力O(lenth*logn)上述复杂度的lenth都是根号n的规模*/#include <cstdio>#include <iostream>#include <cmath>#include <cstring>using namespace std;const int maxn = 3000;const int maxm = 4e6+10;typedef unsigned long long ui;ui P = 3,P_power[maxn];struct node{ int index,left,right,lenth; int is_r; ui f_hash,b_hash; char s[maxn]; void roll(){ if(is_r == 1){ is_r = 0; for(int i = 0 ,j = lenth-1; i <= j; i++,j--) swap(s[i],s[j]); } } void print(){ //roll(); if(is_r == 0) for(int i = 0; i < lenth ; i++) cout <<s[i]; else for(int i = lenth-1; i >= 0 ; i--) cout <<s[i]; cout <<endl; printf("block[%d].left = %d right = % d lenth = %d f_hash = %d b_hash = %d\n",index,left,right,lenth,f_hash,b_hash); } ui getb_hash(){ ui tmp = 0; for(int i = lenth-1 ;i >= 0 ; i--) tmp = tmp *P+s[i]-'0'+1; return tmp; } ui getf_hash(){ ui tmp = 0; for(int i = 0 ;i <lenth ; i++) tmp = tmp *P+s[i]-'0'+1; return tmp; }}block[maxn];int n,m,low_size,up_size,num_block,cp,pos,num,p1,p2,tot;char ini[maxm],c[maxn],d[maxn];void init(){ scanf("%s",ini); up_size = sqrt(n+m);low_size = up_size/2; //printf("up _ size = %d low = %d\n",up_size,low_size); block[0].right = 1;num_block = n/low_size; int last_size = n-num_block*low_size+low_size; int pos = 0; //1~倒数第二块 for(int i = 1; i < num_block ; i++){ ui tmp = 0,bk = 0; block[i].lenth = low_size;block[i].left = i-1;block[i].right = i+1;block[i].index = i; for(int j = 0 ;pos < n && j < block[i].lenth;j++, pos++){ block[i].s[j] = ini[pos]; tmp = tmp*P+ini[pos]-'0'+1; } for(int j = block[i].lenth-1; j >= 0; j--) bk = bk*P+block[i].s[j]-'0'+1; block[i].f_hash = tmp;block[i].b_hash = bk; //cout <<"hahahah "<<block[i].b_hash<<endl; block[i].is_r = 0; } //最后一块 block[num_block].left = num_block-1;block[num_block].right = maxn-1;block[maxn-1].left = num_block;block[maxn-1].index = maxn-1; block[num_block].lenth = last_size;block[num_block].index = num_block;block[num_block].is_r = 0; for(int j = 0;pos < n ;j++,pos++){ block[num_block].s[j] = ini[pos]; } block[num_block].f_hash = block[num_block].f_hash;block[num_block].b_hash = block[num_block].b_hash;}void separate(int s_wi){ ++num_block; int l1 = block[s_wi].lenth/2; int l2 = block[s_wi].lenth-l1; block[num_block].is_r = 0; for(int i = l1 ,j = 0; i < block[s_wi].lenth ; i++,j++) block[num_block].s[j] = block[s_wi].s[i]; block[num_block].index = num_block; block[num_block].left = s_wi;block[num_block].right = block[s_wi].right;block[num_block].lenth = l2; block[block[s_wi].right].left = num_block;block[s_wi].right = num_block;block[s_wi].lenth = l1; int c1 = s_wi,c2 = num_block; block[c1].f_hash = block[c1].getf_hash(); block[c2].f_hash = block[c2].getf_hash(); block[c1].b_hash = block[c1].getb_hash(); block[c2].b_hash = block[c2].getb_hash();}void cp1(int pos,int add){ if(pos == 0){ block[block[0].right].roll(); for(int i = block[block[0].right].lenth; i >= 1 ; i--) block[block[0].right].s[i] = block[block[0].right].s[i-1]; block[block[0].right].s[0] = add+'0'; block[block[0].right].lenth++; int c1 = block[0].right; block[c1].f_hash = block[c1].getf_hash(); if(block[block[0].right].lenth > up_size){ separate(block[0].right); } return; } int i,cl = block[0].right; while(pos > block[cl].lenth){ pos-=block[cl].lenth; cl = block[cl].right; } block[cl].roll(); block[cl].lenth++; for(int i = block[cl].lenth; i > pos ; i--) block[cl].s[i] = block[cl].s[i-1]; block[cl].s[pos] = add+'0'; block[cl].f_hash = block[cl].getf_hash(); block[cl].b_hash = block[cl].getb_hash(); if(block[cl].lenth > up_size) separate(cl);}ui get_hash(int len,int p1){ int c1 = block[0].right; int c3,p3 = len+p1-1; while(p1 > block[c1].lenth){ p1 -= block[c1].lenth; p3 -= block[c1].lenth; c1 = block[c1].right; } block[c1].roll(); p1--;//c1块的第p1位置(下标)开始 c3 = c1; while(p3 > block[c3].lenth){ p3 -= block[c3].lenth; c3 = block[c3].right; } block[c3].roll(); ui tmp = 0,tp = 0; if(c1 == c3){//同一个快 for(int i = p1 ; i < p3; i++) tmp = tmp*P+block[c1].s[i]-'0'+1; } else{ for(int i = p1 ;i < block[c1].lenth; i++) tmp = tmp*P+block[c1].s[i]-'0'+1; for(int i = c1 ; i != block[c3].left ;i = block[i].right) tmp = tmp*P_power[block[block[i].right].lenth]+block[block[i].right].f_hash; for(int i = 0 ; i < p3; i++) tp = tp*P+block[c3].s[i]-'0'+1; tmp = tmp*P_power[p3]+tp; } return tmp;}bool se_check(int len,int p1,int p2){ ui k1 = get_hash(len,p1); ui k2 = get_hash(len,p2); if(k1 == k2) return true; else return false;}int cp4(int p1,int p2){ int l = 1, r = tot - p2+1,ans = 0; while(l <= r){ int mid = (l+r)/2; if(se_check(mid,p1,p2)){ ans = max(ans,mid); l = mid+1; } else r = mid-1; } return ans;}void check(){ for(int i = block[0].right ; i != maxn-1 ; i= block[i].right){ block[i].print(); }}void _union(int cl){ int oth = block[cl].right; block[block[oth].right].left = cl; block[cl].right = block[oth].right; for(int i = block[cl].lenth ,j = 0; j < block[oth].lenth ;i++,j++) block[cl].s[i] = block[oth].s[j]; block[cl].lenth = block[cl].lenth+block[oth].lenth; block[cl].f_hash = block[cl].getf_hash(); block[cl].b_hash = block[cl].getb_hash(); if(block[cl].lenth > up_size) separate(cl);}void cp2(int pos){ int cl = block[0].right; while(pos > block[cl].lenth){ pos -= block[cl].lenth; cl = block[cl].right; } block[cl].roll(); for(int i = pos-1 ;i < block[cl].lenth-1 ; i++){ block[cl].s[i] = block[cl].s[i+1]; } block[cl].lenth--; block[cl].f_hash = block[cl].getf_hash(); block[cl].b_hash = block[cl].getb_hash(); if( block[cl].lenth < low_size) { if(block[cl].left == 0 && block[cl].right == maxn-1) return; if(block[cl].right == maxn-1 ){ block[block[cl].left].roll(); _union(block[cl].left); } else { block[block[cl].right].roll(); _union(cl); } }}void cp3(int p1,int p2){ //check(); int c1 = block[0].right; while(p1 > block[c1].lenth){ p1 -= block[c1].lenth; c1 = block[c1].right; } block[c1].roll(); //block[c1].print(); int c2 = block[0].right; while(p2 > block[c2].lenth){ p2 -= block[c2].lenth; c2 = block[c2].right; } block[c2].roll(); // block[c2].print(); if(c1 == c2){ for(int i = p1-1 ,j = p2-1; i <= j ; i++,j--){ swap(block[c1].s[i],block[c1].s[j]); } block[c1].f_hash = block[c1].getf_hash(); block[c1].b_hash = block[c1].getb_hash(); return; } for(int i = block[c1].right ; i != c2; ){ int j= block[i].right; swap(block[i].right,block[i].left); swap(block[i].f_hash,block[i].b_hash); block[i].is_r ^= 1; i = j; // cout <"in"; } if(block[c1].right != c2){ swap(block[c1].right , block[c2].left); block[block[c2].left].right = c2; block[block[c1].right].left = c1; } int lenc = 0,lend = 0; for(int i = 0 ; i < p1-1;i++) c[lenc++] = block[c1].s[i]; for(int i = p2-1 ; i >= 0 ; i--) c[lenc++] = block[c2].s[i]; for(int i = block[c1].lenth-1; i >= p1-1 ; i--) d[lend++] = block[c1].s[i]; for(int i = p2; i < block[c2].lenth ; i++) d[lend++] = block[c2].s[i]; for(int i = 0 ; i < lenc ; i++){ //cout <<c[i]; block[c1].s[i] = c[i]; } // cout <<endl; for(int i = 0 ; i < lend ; i++){ block[c2].s[i] = d[i]; // cout <<d[i]; } // cout <<endl; block[c1].lenth = lenc;block[c2].lenth = lend; block[c1].f_hash = block[c1].getf_hash(); block[c2].f_hash = block[c2].getf_hash(); block[c1].b_hash = block[c1].getb_hash(); block[c2].b_hash = block[c2].getb_hash(); // cout <<"len1 = "<<lenc <<" lenb = "<<lend<<endl; if(lenc > up_size) separate(c1); if(lend > up_size) separate(c2); if(lenc < low_size){ int cl = c1; //block[cl].print(); if(block[cl].left == 0 && block[cl].right == maxn-1) return; if(block[cl].right == maxn-1 ){ block[block[cl].left].roll(); _union(block[cl].left); } else { block[block[cl].right].roll(); _union(cl); } } if(lend < low_size){ int cl = c2; if(block[cl].left == 0 && block[cl].right == maxn-1) return; if(block[cl].right == maxn-1 ){ block[block[cl].left].roll(); _union(block[cl].left); } else { block[block[cl].right].roll(); _union(cl); } }}void sov(){ tot = n; for(int ca = 1; ca <= m ; ca++){ scanf("%d",&cp); if(cp == 1){ tot++; scanf("%d%d",&pos,&num); cp1(pos,num); //check(); } if(cp == 2){ tot--; scanf("%d",&pos); cp2(pos); //check(); } if(cp == 3){ scanf("%d%d",&p1,&p2); cp3(p1,p2); //block[2].print(); //check(); } if(cp == 4){ scanf("%d%d",&p1,&p2); // check(); printf("%d\n",cp4(p1,p2)); } }}int main(){ freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); P_power[0] = 1; for(int i = 1; i < maxn-1 ; i++) P_power[i] = P_power[i-1]*P; scanf("%d%d",&n,&m); init(); sov();}/*12 1000001000011001 0 14 2 41 1 14 3 41 1 04 2 81 3 04 3 51 7 14 6 91 8 04 1 82 84 6 92 74 3 52 34 2 82 14 3 43 2 93 1 34 1 73 1 24 1 8*/
- hash专题
- 海量数据处理专题(三)——Hash
- 海量数据处理专题(三)——Hash
- 海量数据处理专题(三)——Hash
- 海量数据处理专题(三)——Hash
- 海量数据处理专题(三)——Hash
- hash
- Hash
- hash
- hash
- Hash
- hash
- Hash
- HASH
- hash
- hash
- HASH
- hash
- leetcode 404. Sum of Left Leaves
- 安卓学习笔记(七):服务 跟着API指南来学习
- Dlib库【8】——多层神经网络
- 线段相交
- socket 连接超时处理 java
- hash专题
- android studio配置kotlin
- 【Rest】REST和SOAP Web Service的区别比较
- ASP.NET Core(二)【入门】
- Maven学习总结(12)——深入理解maven生命周期和插件
- Zookeeper 初体验之——JAVA API 初探
- Spark基本函数操作实例
- 抓取远程图片保存到本地
- 数据结构 — 浅析堆排序