bzoj3097: Hash Killer I

题目
题解

Solution

如果 b a s e base 是偶数,那么 a . . . . . . . . . a a a ( > 64 a.........aaa(>64 a ) a) b a . . . . . . . a a ( a ba.......aa(a 的数量为前面那么串 a a 的数量 1 ) -1) ,这两个串长度相同, h a s h hash 值相同,显然串是不同的,这样就卡掉了。
如果 b a s e base 是奇数,就比较麻烦了。
v f k vfk 的做法吧:
如果 b a s e base 是奇数的话,现在只考虑 a a b b 两个字母。
a b a|b 表示 a a 能整除 b b 。( o r z orz 具体数学)
设数学上的函数 n o t ( S ) not(S) 表示把字符串 S S 中每个位置的 a 'a' 变成 b 'b' ,把 b 'b' 变成 a 'a' 后形成的字符串。
s t r A . s t r B strA.strB 代表字符串串联。
s t r |str| 表示字符串 s t r str 的长度。
设字符串序列 o r z s t r [ i ] {orzstr[i]} o r z s t r [ 1 ] = " a " , o r z s t r [ i ] = o r z s t r [ i 1 ] . n o t ( o r z s t r [ i 1 ] ) orzstr[1]="a",orzstr[i]=orzstr[i-1].not(orzstr[i-1])
那么 o r z s t r [ i ] = o r z s t r [ i 1 ] 2 |orzstr[i]|=|orzstr[i-1]|*2 。显然这是等比数列,得到: o r z s t r [ i ] = o r z s t r [ 1 ] . 2 i 1 = 2 i 1 |orzstr[i]|=|orzstr[1]|.2^{i-1}=2^{i-1}
h a s h ( s t r ) hash(str) s t r str 的哈希值。
则:
h a s h ( o r z s t r [ i ] ) = h a s h ( o r z s t r [ i 1 ] ) b a s e n o t ( o r z s t r [ i 1 ] ) + h a s h ( n o t ( o r z s t r [ i 1 ] ) ) hash(orzstr[i])=hash(orzstr[i-1])*base^|not(orzstr[i-1])|+hash(not(orzstr[i-1]))
= h a s h ( o r z s t r [ i 1 ] ) b a s e 2 i 2 + h a s h ( n o t ( o r z s t r [ i 1 ] ) ) =hash(orzstr[i-1])*base^{2^{i-2}}+hash(not(orzstr[i-1]))
h a s h ( n o t ( o r z s t r [ i ] ) ) = h a s h ( n o t ( o r z s t r [ i 1 ] ) ) b a s e 2 i 2 + h a s h ( o r z s t r [ i 1 ] ) hash(not(orzstr[i]))=hash(not(orzstr[i-1]))*base^{2^{i-2}}+hash(orzstr[i-1])
两式相减:
h a s h ( o r z s t r [ i ] ) h a s h ( n o t ( o r z s t r [ i ] ) ) hash(orzstr[i])-hash(not(orzstr[i]))
= ( h a s h ( o r z s t r [ i 1 ] ) b a s e 2 i 2 + h a s h ( n o t ( o r z s t r [ i 1 ] ) ) ) ( h a s h ( n o t ( o r z s t r [ i 1 ] ) ) b a s e 2 i 2 + h a s h ( o r z s t r [ i 1 ] ) ) =(hash(orzstr[i-1])*base^{2^{i-2}}+hash(not(orzstr[i-1])))-(hash(not(orzstr[i-1]))*base^{2^{i-2}}+hash(orzstr[i-1]))
= ( h a s h ( o r z s t r [ i 1 ] ) h a s h ( n o t ( o r z s t r [ i 1 ] ) ) ) ( b a s e 2 i 2 1 ) =(hash(orzstr[i-1])-hash(not(orzstr[i-1])))*(base^{2^{i-2}}-1)
这让我们发现, h a s h ( o r z s t r [ i ] ) h a s h ( n o t ( o r z s t r [ i ] ) ) hash(orzstr[i])-hash(not(orzstr[i])) 似乎是个神奇的东西。而我们的目的实际上是要找两个字符串 s t r A , s t r B strA,strB 使得
h a s h ( s t r A ) = h a s h ( s t r B ) ( m o d ( 2 64 ) ) hash(strA)=hash(strB)(mod(2^{64}))
相当与
2 64 [ h a s h ( s t r A ) h a s h ( s t r B ) ] 2^{64}|[hash(strA)-hash(strB)]
设数列 f [ i ] {f[i]} f [ i ] = h a s h ( o r z s t r [ i ] ) h a s h ( n o t ( o r z s t r [ i ] ) ) f[i]=hash(orzstr[i])-hash(not(orzstr[i]))
这样就有:
f [ i ] = f [ i 1 ] ( b a s e 2 i 2 1 ) f[i]=f[i-1]*(base^{2^{i-2}}-1)
还是有点不爽啊……我们再设数列 g [ i ] {g[i]} g [ i ] = b a s e 2 i 1 1 g[i]=base^{2^{i-1}}-1
于是能写成:
f [ i ] = f [ i 1 ] g [ i 1 ] f[i]=f[i-1]*g[i-1]
f [ i ] = f [ 1 ] g [ 1 ] g [ 2 ] . . . g [ i 1 ] f[i]=f[1]*g[1]*g[2]*...*g[i-1]
然后发现一个神奇的事情?
b a s e base 是奇数,则 b a s e base 的任意正整数次方也一定是奇数。所以对于任意的 i i 必有 g [ i ] g[i] 为偶数,所以 2 i 1 f [ i ] 2^{i-1}|f[i]
问题是不是结束了呢……发现没有……这样的话我们要使 2 64 f [ i ] 2^{64}|f[i] ,至少得让 i = 65 i=65 ……然后发现 o r z s t r [ 65 ] |orzstr[65]| 是个天文数字。
发现我们刚才那样分析太坑爹了……
i > 1 i>1 时有:
g [ i ] = b a s e 2 i 1 1 = ( b a s e 2 i 2 1 ) ( b a s e 2 i 2 + 1 ) = g [ i 1 ] g[i]=base^{2^{i-1}}-1=(base^{2^{i-2}}-1)*(base^{2^{i-2}}+1)=g[i-1]* 一个偶数
g [ 1 ] g[1] 显然是偶数吧……
那么 4 g [ 2 ] 4|g[2] 8 g [ 3 ] . . . 8|g[3]...
也就是说 2 i g [ i ] 2^i|g[i]
所以 f [ i ] f[i] 实际上有:
( 2 1 ) ( 2 2 ) ( 2 3 ) . . . ( 2 i 1 ) f [ i ] (2^1)*(2^2)*(2^3)*...*(2^{i-1})|f[i]
2 i ( i 1 ) / 2 f [ i ] 2^{i*(i-1)/2}|f[i]
i i 12 12 时,就有 66 66 2 2 了哟!
这就是卡 b a s e base 为奇数时的方法。 o r z s t r [ 12 ] orzstr[12] n o t ( o r z s t r [ 12 ] ) not(orzstr[12]) 即为所求。

而读入中 b a s e base 既有奇数又有偶数,直接在奇数构造的字符串后面加 64 64 a a 就可以了。

Code

#include<cstdio>
#include<cstring>
int i,now,j;
char s[1<<12];
int main(){
	puts("2113 1024");
	putchar(s[now=1]+97);
	for (i=0;i<11;i++,now<<=1)
		for (j=0;j<now;j++) putchar((s[now+j]=s[j]^1)+97);
	for (i=0;i<65;i++) putchar('a');
}

猜你喜欢

转载自blog.csdn.net/xumingyang0/article/details/85059633