Recover an RBS
传送门
题意:
给出a, b序列,c序列刚开始有些位置是有值的,题目已经给出,其余位置为0,对于0的位置要求从a, b对应的位置取一个值,最后使整个c构成一个序列,问可以构成多少个可以构成的序列,结果对1e9 + 7取模
思路:
可以先确定哪些位置是确定不变的
- 如果a, b的元素相等,那就是不变的
- 去处理那些题目已经确定的位置,根据那些位置可以推出的其他所有位置的情况也只可能只有一个
- 去处理那些题目已经确定的位置,根据那些位置可以推出的其他所有位置的情况也只可能只有一个
在已经得知那些确定的位置之后剩下的位置,可以发现如果可以跳来跳去去构成一个环,那对答案的贡献就是 * 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
*/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具