zoukankan      html  css  js  c++  java
  • 随机化的奇妙用法

    一、随机化避免碰撞

    1.对数字进行随机化后可以避免数字发生碰撞。

    例题:P2087 GTY的人类基因组计划2

    这道题的唯一难点是判断一个房间里的一群人是否出现过。

    可以考虑对于每一个人赋予他一个rand值,然后用rand值的和判断是否出现过。

    比如有编号1,2,3的三个人,假设他们的rand值为11,45,14

    1和2同时出现的时候他们的rand值之和sum_rand=56而他们的编号之和sum_pos=3

    发现sum_rand!=rand[3]但是sum_pos=pos[3]

    用rand有效的减小了碰撞的概率。

    那么这道题的思路就非常简单了。

    map<int, int> vis;
    set<int> s;
    int a[MAXN], to[MAXN], n, m, q, num[MAXN], h[MAXN];
    
    signed main()
    {
        srand(2004 + 8 + 21);
        n = read(), m = read(), q = read();
        for (int i = 1; i <= n; i++) 
        {
            a[i] = rand() * rand() % 1145141919 * (rand() * rand() % 19260817) * 810;
            h[1] ^= a[i];
            to[i] = 1;
            num[1]++;
        }
        s.insert(1);
        while (q--)
        {
            char opt;
            cin >> opt;
            int x = read(), y = read();
            if (opt == 'C')
            {
                if (to[x] == y) continue;
                s.erase(to[x]);
                s.erase(y);
                h[to[x]] ^= a[x];
                h[y] ^= a[x];
                num[to[x]]--;
                num[y]++;
                if (!vis[h[to[x]]]) s.insert(to[x]);
                if(!vis[h[y]]) s.insert(y);
                to[x] = y;
            }
            if (opt == 'W')
            {
                int ans = 0;
                auto it = s.lower_bound(x);
                for (; it != s.end() && *it <= y; it = s.lower_bound(x))
                {
                    vis[h[*it]] = 1;
                    ans += num[*it];
                    s.erase(it);
                }
                cout << ans;
                puts("");
            }
        }
        return 0;
    }
    View Code

    2.多次随机化避免碰撞

    例题: P2312 解方程

    直接算会溢出,可以随机取几个模数,

    对于一个数x如果取模后计算出来的方程结果是0,那么这个x就是一个答案。

    int n, m, a[MAXN], k[MAXN], cnt, t, ans, sum;
    
    int calc(int x, int MOD)
    {
        sum = 0;
        for (int i = n; i >= 1; i--)
        {
            sum = ((sum + a[i]) * x) % MOD;
        }
        sum = (sum + a[0]) % MOD;
        return !sum;
    }
    
    signed main()
    {
        n = read(), m = read();
        for (int i = 0; i <= n; i++)
        {
            a[i] = read();
        }
        for (int i = 1; i <= m; i++)
        {
            if (calc(i,rand())&&calc(i,rand()))
            {
                t = 1;
                ans++;
                k[++cnt] = i;
            }
        }
        if (!t)
        {
            puts("0");
            return 0;
        }
        printf("%lld", ans);
        puts("");
        for (int i = 1; i <= cnt; i++)
        {
            printf("%lld", k[i]);
            puts("");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    C++ 字符数组
    C++ 从函数返回数组
    C++给函数传数组参数
    串行通信的三种方式
    进程间通信pipe和fifo
    嵌入式开发基本知识
    查找算法
    排序算法
    offsetof与container_of宏[总结]
    uboot自定义添加命令
  • 原文地址:https://www.cnblogs.com/dead-gun/p/12945719.html
Copyright © 2011-2022 走看看