康拓展开-排列的hash
對(duì)于一個(gè)集合內(nèi)所有元素的排列,康拓展開(kāi)是一個(gè)無(wú)沖突的hash法。其規(guī)則便是將排列在邏輯上排好序,然后每個(gè)排列的序號(hào)即是hash值。
關(guān)鍵就在如何快速求出序號(hào)和快速還原啦。
首先我們確定一好集合內(nèi)各元素的大小關(guān)系,然后開(kāi)始處理。
生成:
對(duì)于一個(gè)排列(長(zhǎng)度為n),我們要算出它前面有多少比它小的序列,如果序號(hào)從0開(kāi)始,那么這個(gè)數(shù)字就是它的序號(hào)。
有點(diǎn)類(lèi)似數(shù)位DP的處理,我們從最高位看起(設(shè)位x),如果一個(gè)排列的最高位比它小,那么這個(gè)排列一定比它小。
所以設(shè)集合中比x小的元素有k個(gè),如果最高位確定,那么后面的幾位可以隨意排列,顯然有(n-1)!種,那么一共就有k*(n-1)!種。
最高位確定了,我們就考慮最高位相等時(shí)次高位的情況,處理方法是類(lèi)似的,但是在計(jì)算k的時(shí)候,因?yàn)樵扔眠^(guò)的數(shù)字已經(jīng)不能出現(xiàn)在后面了,所以統(tǒng)計(jì)比x'小的元素時(shí)不能把他們算進(jìn)去,然后乘上(n-2)!即可。
每一位都這樣處理,就可以不重不漏啦。
復(fù)原:
因?yàn)椴淮嬖跊_突,在系數(shù)k不超過(guò)n-i時(shí),這個(gè)多項(xiàng)式的值我們可以用除法和取余來(lái)實(shí)現(xiàn)復(fù)原。
設(shè)hash值為val
k=val/(n-1)!
val%=(n-1)!//寫(xiě)成val-=k*(n-1)!也是可以的
k即是比當(dāng)前位小的元素個(gè)數(shù),val把當(dāng)前項(xiàng)減去。
即可還原排列了。
代碼:
class cantor
{
public:
#define siz 6
char c[siz]= {'','','','','',''};
LL w[siz];
bool vis[siz];
cantor()
{
w[]=;
for(int i=; i<siz; i++)
w[i]=w[i-]*i;
}
void init()
{
for(int i=; i<siz; i++)
vis[i]=false;
}
LL makeCanto(string s)
{
init();
LL rec=;
for(int i=; i<siz; i++)
{
int d=;
for(int j=; j<siz; j++)
{
if(vis[j])
continue;
if(c[j]!=s[i])d++;
else
{
vis[j]=true;
break;
}
}
rec+=w[siz-i-]*d;
}
return rec;
}
string recover(LL val)
{
init();
string s="";
for(int i=siz-; i>=; i--)
{
LL te=val/w[i];
val%=w[i];
for(int j=,cnt=-; j<siz; j++)
{
if(vis[j])continue;
else cnt++;
if(cnt==te&&!vis[j])
{
s+=c[j];
vis[j]=true;
break;
}
}
}
return s;
}
} ;
總結(jié)
以上是生活随笔為你收集整理的康拓展开-排列的hash的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: C#操作Excel文件
- 下一篇: .netcore centos环境搭建实