跳到主要内容

Hash Killer I

· 阅读需 2 分钟

好烦人啊,竟然要卡我最喜欢用的自然溢出,你知道的,OI Wiki真的很好用

首先对于basebase为偶数的情况,只要ll够大(大于64)则一定会出现basel≡0(mod264)base^l \equiv 0(mod 2^{64})

然后对于basebase为奇数的情况,使用ThueMorseThue Morse序列(一个0101序列满足a0=0a_0=0,nn为偶数时an=an2a_n=a_{ \frac{n}{2}},nn为奇数an=1−an−1a_n=1-a_{n-1})来构造

定义¬x \lnot x是对0101串xx按位取反的结果

则对于ThueMorseThue Morse序列ss,s0=0,sn=sn−1+¬sn−1s_0=0,s_n=s_{n-1}+ \lnot s_{n-1}

对这两个做差得到

sn−¬sn=(sn−1×base2n−2+¬sn−1)(¬sn−1×base2n−2+sn−1)=(sn−1−¬sn−1)×(base2n−2−1)\begin{aligned} s_n- \lnot s_n&=(s_{n-1} \times base^{2^{n-2}} + \lnot s_{n-1})( \lnot s_{n-1} \times base^{2^{n-2}} + s_{n-1})\\ &=(s_{n-1}- \lnot s_{n-1}) \times ( base^{2^{n-2}}-1 ) \end{aligned}

进行换元fn=sn−¬sn,gn=base2n−2−1f_n=s_n- \lnot s_n,g_n=base^{2^{n-2}}-1

所以fn=fn−1×gnf_n=f_{n-1} \times g_n,进一步得到fn=f1×∏i=2ngif_n=f_1 \times \prod_{i=2}^{n}g_i

所以不难发现gg一定是一个偶数

再简短一点的方式,平方差可得gn=base2n−2−1=(base2n−3−1)×(base2n−3+1)g_n=base^{2^{n-2}}-1=(base^{2^{n-3}}-1) \times (base^{2^{n-3}}+1)

后半部分一定是一个偶数对吧,满足了我们的条件

然后根据计算,只要n=12n=12就可以卡掉自然溢出(详细证明过程见OI Wiki)

int n=1<<12, len=n>>1;
cout<<n<<" "<<len<<"\n";
for( int i=0;i<n;i++ ) cout<<char( 'a'+( __builtin_popcount( i ) & 1 ) );
//luogu上能过,但是nsoj要wrong(没写spj)