Good Bye 2022: 2023 is NEAR D. Koxia and Game

原题链接:Problem - D - Codeforces

题面: 

大概意思就是给你一个数组a和数组b,你自己设计一个数组c,Koxia可以从a[i]、b[i]和c[i]中选一个,而Mahiru只能从另外两个里选一个,问你有多少个数组c一定能使Mahiru选择的数字形成一个1~n的排列。

 思路:

首先我们需要知道,a[i]、b[i]和c[i]中一定要有两个是相同的,并且Koxia必须选择那个和另外两个不同的数(或者三个数都相同了)。这是为什么呢?因为若a[i]、b[i]和c[i]都是不相同的,那么Mahiru的选择的数就不是固定的了,这样就肯定形成不了排列。所以我们要让Mahiru的选择固定下来。

为了使得Mahiru的选择固定下来,三个数中则至少有两个数是一样的,这样子Koxia就可以选择那个不同的数,使得Mahiru的选择固定了。而若a[i]和b[i]原本就一样的话,c[i]可以选任何值,对方案的贡献值为*n,若不一样的话,则c[i]只能等于a[i]或者b[i]。对方案的贡献值可能为*2。为什么是可能呢?因为有时候并不是两个选择都能有相应的答案。

我们在点a[i]与点b[i]之间连一条边,若d能是一个排列,则每个结点都能被恰好被指一次,每条边只能指向一个节点。

以题目中的样例来打个比喻:

3

1 2 2

1 3 3

可以画成下面这样的图

 对于结点2、3,我们有两种选法使得每个结点都能被恰好被指一次

 

所以对于结点2、3我们有两种选法,而且结点1是一个自环,c[1]在1~3中都可以选,所以对于样例一,我们总共有3*2=6种选法。

而样例中的:

5

3 3 1 3 4

4 5 2 5 5

可以这样画:

它肯定没有解,这是为什么呢?因为1和2都不可能都选到。相信有一部分同学已经看出来了,若有解,则每个连通块都必须有一个环,也就是每个联通块不能有两个及以上的环(因为若一个连通块形成不了环了,那必然会有某个连通块会多出环来)。

最后在有解的情况下,若结点a[i]=b[i],则方案数*n,因为c[i]无论怎么选都不会使得本来有解的情况变成无解,所c[i]可以在1~n中任选。若结点a[i]!=b[i],则看a[i]和b[i]是否在一个环中,若在一个环中,就说明我们可以在这个环中逆时针选一次,顺时针选一次,方案数*2。若无环则方案数不变。

using mint = simpler::modint<998244353>;
int find(int x) {
	return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void solve() {
	mint ans = 1;
	int n;
	cin >> n;
	FOR(1, n) fa[i] = i, cnt[i] = 0;
	FOR(1, n) cin >> a[i];
	FOR(1, n) cin >> b[i];
	FOR(1, n) {
		int fx = find(a[i]), fy = find(b[i]);
		if (a[i] == b[i]) ans *= n, cnt[fy]++;//若形成自环则方案数*n
		else if (fx == fy) ans *= 2, cnt[fy]++;//若形成环了则方案数*2 
		else  fa[fx] = fy, cnt[fy] += cnt[fx];//若无环则方案数不变 
		if (cnt[fy] > 1) {//判断是否形成了两个及以上的环
			cout << 0 << endl;
			return;
		}
	}
	cout << ans << endl;
}

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值