【bzoj4917】Hash Killer IV 乱搞
题目描述
已知函数:
unsigned int Hash(unsigned int v)
{
unsigned int t = v;
t = t + (t << 10);
t = t ^ (t >> 6);
t = t + (t << 3);
t = t ^ (t >> 11);
t = t + (t << 16);
return t;
}
的返回值为t,求传入的参数v。
输入
第一行包含一个正整数Q(1<=Q<=100000),表示询问的个数。
接下来Q行,每行一个整数t(0<=t<2^32),表示询问的t。
输入数据保证对于每个t至少存在一组解。
输出
对于每组数据输出一行一个整数,即合法的v,若有多组可行解,输出任意一组。
样例输入
4
614278301
1228622139
1841720774
2457244278
样例输出
1
2
3
4
题解
乱搞
考虑到函数中的五个操作都是可逆的:
$kv=t$可以直接用欧拉定理$a^{\varphi(p)}\mod p=1$求出$k$的逆元,乘上$t$即可得到$v$。
$v^(v>>k)=t$中由于$v>>k$的前$k$位都是$0$,因此$v$的前$k$位就是$t$的前$k$位,然后异或上$t$的$k+1...2k$位可以计算出v的第$k+1...2k$位,以此类推。
于是倒过来乱搞即可。
然后卡卡常数就rank 1了好开心(代码中未加入相关优化)
#include <cstdio> typedef unsigned int uint; uint work(uint x , int y) { uint ans = 0 , last = 0 , val = ((1u << y) - 1) << (32 - y); int i; for(i = 31 ; val ; i -= y , val >>= y , last >>= y) last = (last ^ x) & val , ans += last; return ans; } int main() { int T; scanf("%d" , &T); while(T -- ) { uint x; scanf("%u" , &x); x *= 4294901761u; x = work(x , 11); x *= 954437177u; x = work(x , 6); x *= 3222273025u; printf("%u\n" , x); } return 0; }