随机化的奇妙用法

一、随机化避免碰撞

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

 

posted @ 2020-05-24 08:07  dead_gun  阅读(159)  评论(0编辑  收藏  举报