Loading

【题解】ABC234Ex - Distinct Multiples

如果不考虑 \(A_i\neq A_j\) 的条件非常好做,不难想到将这个条件容斥掉。

这等价于从 \(\dfrac{N(N - 1)}{2}\) 个二元组中钦定一些使得对应两端相同,表现在图中就是求连通块个数和对应的 \(\rm lcm\)

所以我们不难设计 DP,\(f_{S}\) 表示集合为 \(S\) 的所有点的答案,我们枚举包含集合中最小点的连通块 \(T\)\(f_{S} = \sum\limits_{T}f_{S/T}g_{T}\)

其中 \(g_{S}\) 表示集合为 \(S\) 的连通块容斥后的答案。由于联通块中所有数相同,我们求出它们的 \(\rm lcm\)\(m/\rm lcm\) 就是填数的方案。

但是我们还要计算容斥系数,选了奇数条边的系数为 \(-1\),偶数条边的系数为 \(1\)

如果不要求连通且点数 \(\ge 2\),那么选奇数条边和偶数条边方案相同,总和为 \(0\)

考虑枚举点 \(1\) 所在集合 \(T\),如果 \(|S/T|\ge 2\),那么这 \(\ge 2\) 个点选奇数条边和偶数条边方案相同,正负相消不用考虑。

再考虑求 \(|S/T| = 1\) 的情况,其中 \(T\) 必须包含点 \(1\),所以方案数有 \(|S| - 1\)

如果我们记点集大小为 \(n\) 的容斥系数为 \(h_n\),则有 \(h_{n} = -(n - 1) h_{n - 1}\),预处理一下即可。

时间复杂度 \(\mathcal{O}(3^n)\),瓶颈在于 DP。

#define N 17
int n;LL m, g[1 << N], bt[1 << N], f[1 << N], h[N], d[N];
int main() {
	read(n), read(m);
	rp(i, n)read(d[i]);
	g[0] = 1; int w = 1 << n;
	rp(i, w - 1){
		bt[i] = bt[i >> 1] + (i & 1);
		rep(j, 0, n - 1)if((i >> j) & 1){g[i] = lcm(g[i ^ (1 << j)], d[j + 1]);break;}
	}
	rp(i, w - 1)g[i] = (m / g[i]) % P;
	h[1] = 1;
	rep(i, 2, n)h[i] = (P - i + 1LL) * h[i - 1] % P;
	f[0] = 1;
	rp(i, w - 1){
		for(int j = i; j; j = (j - 1) & i)if(j & (i & -i))
			ad(f[i], f[i ^ j] * 1LL * g[j] % P * h[bt[j]] % P);
	}
	cout << f[w - 1] << endl;
	return 0;
}
posted @ 2022-02-03 19:47  7KByte  阅读(185)  评论(0编辑  收藏  举报