其他分享
首页 > 其他分享> > Recover an RBS

Recover an RBS

作者:互联网

传送门
题意:

给出a, b序列,c序列刚开始有些位置是有值的,题目已经给出,其余位置为0,对于0的位置要求从a, b对应的位置取一个值,最后使整个c构成一个序列,问可以构成多少个可以构成的序列,结果对1e9 + 7取模

思路:

可以先确定哪些位置是确定不变的

  • 如果a, b的元素相等,那就是不变的
  • 去处理那些题目已经确定的位置,根据那些位置可以推出的其他所有位置的情况也只可能只有一个
  • 去处理那些题目已经确定的位置,根据那些位置可以推出的其他所有位置的情况也只可能只有一个

在已经得知那些确定的位置之后剩下的位置,可以发现如果可以跳来跳去去构成一个环,那对答案的贡献就是 * 2,所以问题就转换为剩下的位置可以构成多少个环,要判断数字环的话,可以用并查集,转换为连边的思想,记录数量为count, 最后的答案是\(2^{count}\)

点击查看代码
#include <bits/stdc++.h>
#define endl '\n'
#define IOS ios::sync_with_stdio(false);
#define PII pair<int, int>
using namespace std;
 
typedef long long ll;
const ll MOD = 1e9 + 7;
const int N = 1e5 + 10;
 
ll quick_pow(ll base, ll power)
{
    ll result = 1ll;
    while (power)
    {
        if (power & 1)  //当前的指数为奇数
        {
            result = (result % MOD * base % MOD) % MOD; //将当前多余出来的底数单独先记录下来,让他重新能够对半
        }
        base = (base % MOD * base % MOD) % MOD; //能够执行到这一步说明这个底数还可以对半相乘,或者这个对半相乘没有作用
        power >>= 1;    //如果为1的话,最后就为0了
    }
    return result;
}
 
int T, n;
int a[N], b[N], c[N], fa[N];
 
struct Node
{
    int a, b, c, id;
} aa[N], bb[N];
 
void Init()
{
    for (int i = 1; i <= n; ++i)
    {
        fa[i] = i;
    }
}
 
int find(int x)
{
    if (x == fa[x])
        return x;
    else
        return fa[x] = find(fa[x]);    
}
 
int main()
{
	IOS; cin.tie(0), cout.tie(0);
    cin >> T;
    while (T--)
    {
        cin >> n;
        queue<Node> q;
        map<int, int> mp;
        Init();
        for (int i = 1; i <= n; ++i)
        {
            cin >> a[i];
        }
        for (int i = 1; i <= n; ++i)
        {
            cin >> b[i];
        }
        for (int i = 1; i <= n; ++i)
        {
            cin >> c[i];
            if (c[i] != 0 || a[i] == b[i])  //两个位置的元素相同也是唯一确定的
            {
                if (a[i] == b[i])
                    c[i] = a[i];
                q.push({a[i], b[i], c[i], i});   //4个元素全插入
                mp[i] = 1;  //对位置进行标记
            }
        }
        for (int i = 1; i <= n; ++i)
        {
            aa[a[i]].a = a[i];
            aa[a[i]].b = b[i];
            aa[a[i]].c = c[i];
            aa[a[i]].id = i;
            bb[b[i]].a = a[i];
            bb[b[i]].b = b[i];
            bb[b[i]].c = c[i];
            bb[b[i]].id = i;
        }
 
        //先把肯定确定的位置数量给记录标记出来
        while (!q.empty())  //将确定位置的全标记
        {
            Node temp = q.front();
            q.pop();
            if (temp.a == temp.b)   //说明这a[i], b[i]相同,不用考虑
            {
                continue;
            }
            if (temp.a == temp.c)   //a, b之间我选择了a, b数组里面的a的位置就确定了
            {
                int id = bb[temp.a].id; //b数组里面被影响对应的id
                if (c[id])  //说明题目已经给你确定了
                {
                    continue;
                }
                else    //这个位置是确定的,但是题目没有给你确定
                {
                    c[id] = bb[temp.a].a;
                    bb[temp.a].c = c[id];
                    q.push({bb[temp.a].a, bb[temp.a].b, bb[temp.a].c, bb[temp.a].id});
                }
            }
            else if (temp.b == temp.c)  //a, b之间我选择b, a数组里面的b位置就确定了
            {
                int id = aa[temp.b].id;
                if (c[id])  //说明题目已经给你确定了
                {
                    continue;
                }
                else
                {
                    c[id] = aa[temp.b].b;   //注意这里有更新
                    aa[temp.b].c = c[id];
                    q.push({aa[temp.b].a, aa[temp.b].b, aa[temp.b].c, aa[temp.b].id});
                }
            }
        }
 
        //下面就是讨论剩下的没标记的,可以构成多少个环,因为如果是环的话,一个变,整体变,每个环的贡献都 * 2
        //数字看环的个数并查集考虑
        int count = 0;
        for (int i = 1; i <= n; ++i)
        {
            if (c[i])   //c[i]的位置是确定的
            {
                continue;
            }
            else
            {
                int fax = find(a[i]);
                int fay = find(b[i]);
                if (fax == fay) //他们的祖先已经相等了,但是还是要给他们连边,那就构成了环
                {
                    ++count;
                }
                else
                {
                    fa[fax] = fay;
                }
            }
        }
        cout << quick_pow(2ll, count) << endl;  //最后的答案就是并查集环的个数的2的count次,因为每次的贡献都 * 2
        
    }
	return 0;
}
/*
1
8
1 6 4 7 2 3 8 5
3 2 8 1 4 5 6 7
1 0 0 7 0 3 0 5
*/

标签:int,ll,位置,RBS,base,result,Recover,MOD
来源: https://www.cnblogs.com/jumo-xiao/p/16507909.html