abc349F 题解

我都自闭了,赛后一分钟调出来。

题意

给定一个长度为 \(n\) 的序列,现在从原序列中取一个子序列,使得子序列中元素的最小公倍数为 \(m\)。求有多少个子序列满足条件,\(\mod 998244353\)

\(1\le n\le 2\times 10^5\)

\(1\le A_i,m\le 10^{16}\)

思路

一个很明显的性质就是,如果先将 \(m\) 分解质因数成 \(\prod p_k^{c_k}\) 的形式,子序列 \(U\) 中的数也分解质因数,那么明显,对于一个子序列成为答案的充要条件是:

  • 对于 \(\forall p_k\) ,有 \(\max\limits_{v\in U} c_v=c_k\)
  • \(m\) 的质因数集合等于子序列所有数子集的并集

通俗的说,就是对于 \(m\) 的每个质因数,能在子序列找到一个数,使它们的最高次幂相同。

进行一些适当的预处理,排除掉不可能贡献的数。
这个时候,问题转化为:

  • 有若干个序列,从中选取若干个序列,使得对于 \(\forall i,\max a_i=b_i\)

举个例子:
不妨令 \(m=24\) ,此时 \(m=2^3\times 3\)
那么,\(6=2\times 3\)\(12=2^2\times 3\)\(8=2^3\)

那么原问题化为:给定 \(a=\{3,1\}\)\(3\) 个序列 \(\{1,1\},\{2,1\},\{3,0\}\) ,很明显只有 \(3\) 种方案满足要求。

那么我们知道,只有 \(a_i=b_i\),才会产生合法的贡献。我们计如果第 \(i\) 个数第 \(j\) 位满足这个条件,那么 \(d_{i,j}=1\),否则为 \(0\)

现在,问题转化成一个通俗模型:

  • 给定 \(n\) 个长度为 \(k\)\(01\) 串,求它们或起来全为 \(1\) 的方案数。

很明显有个 \(O(n2^k)\) 做法,然后被出题人卡掉了。

蒟蒻不会高级算法,只会朴素容斥。

思路:正难则反,钦定其中某些位数为 \(0\),求方案。
这个很好做,把这些位数全为 \(0\) 的数个数求出来 为\(cnt\),然后贡献就是 \(2^{cnt}\)

然后计算过程发现就是求交集而已,直接上一个 bitset 暴力优化即可。然后就过了。时间复杂度 \(O(\frac{n2^k}{w})\)

code

#include<bits/stdc++.h>
#define N 200005
#define ll long long
using namespace std;
const int mod=998244353;
int n;
ll m,p[N];
int t[N],tot;
int len;
bitset<N> g[16],f;
ll pw[N],ans;
int main()
{
	scanf("%d%lld",&n,&m);
	for(ll i=2;i<=sqrt(m);i++)
	{
		if(m%i) continue;
		p[++tot]=i;
		while(!(m%i)) m/=i,t[tot]++;
	}
	if(m^1) p[++tot]=m,t[tot]=1;
	f[0]=1;
	for(int i=1;i<=n;i++)
	{
		int mask=0,tag=0;
		ll x;
		scanf("%lld",&x);
		for(int j=1;j<=tot;j++)
		{
			int v=0;
			while(!(x%p[j])) x/=p[j],v++;
			if(v>t[j]) 
			{
				tag=1;
				break;
			}
			if(v^t[j]) mask|=(1<<j-1);
		}
		if(x^1||tag) continue;
		++len;
		for(int j=0;j<tot;j++)
			if(mask&(1<<j)) g[j].set(len);
	}
	pw[0]=1;
	for(int i=1;i<=len;i++) pw[i]=(pw[i-1]*2)%mod;
	ans=pw[len];
	for(int i=1;i<(1<<tot);i++)
	{
		int cnt=0;
		f.set();
		for(int j=0;j<tot;j++)
			if(i&(1<<j)) f&=g[j],cnt++;
		if(!(cnt&1)) ans=(ans+pw[f.count()])%mod;
		else ans=(ans+mod-pw[f.count()])%mod;
	}
	if(!tot) ans=(ans-1+mod)%mod;
	printf("%lld",ans);
	return 0;
}

提交记录

跑的飞快,最慢的点 314ms

posted @ 2024-04-13 22:28  g1ove  阅读(70)  评论(0编辑  收藏  举报