acm/oi 中的hash 混淆和随机base

文章讨论了在传统哈希方法容易被针对的情况下,如何采用随机数生成的base进行哈希值计算,以增加安全性。通过使用mt19937engine和自定义的混淆函数,对树节点的哈希值进行处理,降低了被特殊样例破解的可能性。在给定的例题中,该策略用于解决二叉树的对称性检测问题。
摘要由CSDN通过智能技术生成

背景

随着传统竞赛hash被卡的情况频繁发生,如何找到一个稍微难卡的hash成了难题。在oi-wiki上的三种tree-hash都能构造特殊样例直接卡掉,这里讨论的是一种随机的hash

用随机数发生器创建一个base,防止被hack

mt19937 engine(random_device{}());
uniform_int_distribution<long long> rd(1, LLONG_MAX);
long long base = rd(engine);

混淆加密前一个hash

int confound(int x)
{
    x ^= x << 13;
    x ^= x >> 7;
    x ^= x << 17;
    return x;
}

二次混淆当前hash

    hhash[now] + / * = confound(hash[pre]);
    hhash[now] ^= (1 << 20 - 1);

例题

855 div3 G.Symmetree

ac代码

/**
 * @file codeforceModel.cpp
 * @author lighteverthing (wanxinnb@outlook.com)
 * @brief codeforces的答题模板
 * @date 2022-09-30
 * 
 * @copyright Copyright (c) 2022
 * 
 */
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <cstring>
#include <random>
#include <climits>
 
using namespace std;
 
#define random
 
const int maxn = 2E5 + 7;
#define int long long
vector<int> e[maxn];
int dp[maxn];
int hhash[maxn];
 
#ifdef random
mt19937 engine(random_device{}());
uniform_int_distribution<long long> rd(1, LLONG_MAX);
#endif
 
int base = rd(engine);
 
inline void init(int n)
{
    for (int i = 1; i <= n; i ++)
    {
        e[i].clear();
        dp[i] = 0;
    }
}
 
int confound(int x)
{
    x ^= x << 13;
    x ^= x >> 7;
    x ^= x << 17;
    return x;
}
 
void dfs(int now, int fa)
{
    hhash[now] =  base;
    int sum = 0;
    int siz = e[now].size() - (now == 1 ? 0 : 1);
    map<int, int> mp;
 
    for (auto& y : e[now])
    {
        if (y == fa) continue;
        dfs(y, now);
        sum ^= hhash[y];
        mp[hhash[y]] = y;
        hhash[now] +=  confound(hhash[y]);
    }
 
    hhash[now] = hhash[now] ^ (1 << 20 - 1);
 
    if (sum == 0)
    {
        dp[now] = true;
    }
    else
    {
        if (siz % 2 == 1 && dp[mp[sum]])
            dp[now] = true;
        else 
            dp[now] = false;
    }
}
 
inline void solve()
{
#ifdef DEBUG
    for (int i = 1; i <= 100; i++);
#endif
    int n;
    cin >> n;
    
    init(n);
    for (int i = 1; i <= n - 1; i ++)
    {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
 
    dfs(1, -1);
    cout << (dp[1] ? "YES" : "NO") << '\n';
}
 
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
 
    int T = 1;
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值