【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;
}

 

 

posted @ 2017-09-21 19:57  GXZlegend  阅读(406)  评论(0编辑  收藏  举报