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