首先一个结论是:只有在 \(Y \bmod X =0\) 时,才有答案。
证明显然,因为 \(\gcd\) 和 \(\operatorname{lcm}\) 的性质,\(a_i\) 和 \(v\) 是 \(X\) 的倍数,\(a_j\) 和 \(v\) 是 \(Y\) 的因数。
那么接下来,因为 \(X\) 和 \(Y\) 是固定的,容易想到将它们分解质因数。
分解质因数你可以使用 Pollard's Rho 算法,但其实有个更简单的做法,我们待会儿介绍。
现在设 \(X=p_1^{cntx_1}p_2^{cntx_2}...p_k^{cntx_k}\),\(Y=p_1^{cnty_1}p_2^{cnty_2}...p_k^{cnty_k}\),把质因数集合定为 \(Y\) 的质因数集合,如果 \(X\) 没有某个质因数 \(p_i\) 则 \(cntx_i=0\) 。
接着把所有 \(a_i\) 和 \(v\) 也分解成这个形式,\(a_i=p_1^{cnt_{i,1}}p_2^{cnt_{i,2}}...p_k^{cnt_{i,k}}\),\(v=p_1^{cntv_1}p_2^{cntv_2}...p_k^{cntv_k}\)。
那么 \(\gcd\) 和 \(\operatorname{lcm}\) 的限制就可以转化为,对于 \(1\le s\le k\),\(\min(cnt_{i,s},cntv_s)=cntx_s\),\(\max(cnt_{j,s},cntv_s)=cnty_s\)。
如果 \(cntx_s=cnty_s\) 的话,显然 \(v\) 必须恰好有 \(cntx_s\) 个 \(p_s\),因为 \(a_i\) 是 \(X\) 的倍数,\(a_j\) 是 \(Y\) 的因数,所以 \(cnt_{i,s}\ge cntx_s\),\(cnt_{j,s}\le cnty_s\),那么一定能够满足限制,所以可以无视这一位,把它删掉了。
如果 \(cntx_s < cnty_s\) 的话,我们分类讨论,发现只有一种情况是不合法的:\(cnt_{i,s}> cntx_s\),\(cnt_{j,s}< cnty_s\),这时候 \(cntv_s\) 既要等于 \(cntx_s\),又要等于 \(cnty_s\),于是就矛盾了。
这时候问题可以转到我们熟悉的二进制上去!设 \(minn_x\) 表示所有是 \(X\) 倍数的 \(a_i\) 对于每个 \(s\),若 \(cnt_{i,s}> cntx_s\) 则第 \(s\) 位为 \(1\),否则为 \(0\),最后的二进制总和为 \(x\) 的有几个。类似地,设 \(maxn_x\) 表示所有是 \(Y\) 因数的 \(a_i\) 对于每个 \(s\),若 \(cnt_{i,s}< cnty_s\) 则第 \(s\) 位为 \(1\),否则为 \(0\),最后的二进制总和为 \(x\) 的有几个。
于是最后的答案就为 \(\sum minn_imaxn_j \,[\,i\&j =0\,]\)。
最后就是,怎么对 \(Y\) 分解质因数。题解给出了一个非常巧妙的做法:先把 \(1\sim 10^6\) 的质数筛出来,把 \(Y\) 在这之间的质因数去掉。那么剩下的数 \(s\) 要么是一个大质数,要么是一个大质数的平方,要么是两个不同的大质数的乘积。是不是一个大质数的平方很容易用 \(\operatorname{sqrtl}\) 判断。接下来,判断 \(s\) 是否等于 \(p\times q\),你发现如果不存在一个 \(a_i\) 是 \(p\) 的倍数但不是 \(q\) 的倍数或是 \(q\) 的倍数但不是 \(p\) 的倍数,那么所有的 \(a_i\) 要么都没有 \(p\)、\(q\) 两个因子,要么都有这两个因子,那么我们可以把 \(p\times q\) 看成一个因子,这对答案不会有影响。所以判断 \(s\) 是否等于 \(p\times q\),只要将 \(s\) 和所有 \(a_i\) 取个 \(\gcd\),若 \(\gcd\) 不等于 \(1\) 也不等于 \(s\),说明找到了 \(p\)、\(q\) 中的一个,就做完了。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10,M=1e6+10;
int n,m,x,y,s,ans,a[N],minn[(1<<15)+10],maxn[(1<<15)+10];
int tot,vis[M],pr[M],p[16],cntx[16],cnty[16];
void find()
{for(int i=1,g;i<=n;i++){g=__gcd(a[i],s);if(g!=1&&g!=s){p[++m]=g,cnty[m]=1;p[++m]=s/g,cnty[m]=1;return;}}p[++m]=s,cnty[m]=1;return;
}
signed main()
{for(int i=2;i<=M-10;i++){if(!vis[i])pr[++tot]=i;for(int j=1;j<=tot&&pr[j]*i<=M-10;j++){vis[pr[j]*i]=1;if(i%pr[j]==0)break;}}scanf("%lld%lld%lld",&n,&x,&y),s=y;for(int i=1;i<=n;i++)scanf("%lld",&a[i]);if(y%x)printf("0");else{for(int i=1;i<=tot;i++){if(s%pr[i]==0){p[++m]=pr[i];while(s%pr[i]==0)s/=pr[i],cnty[m]++;}}if(s>1){int sq=sqrtl(s);if(sq*sq==s)p[++m]=sq,cnty[m]=2;else find();}for(int i=1,s=x,j=0;i<=m;i++){while(s%p[i]==0)cntx[i]++,s/=p[i];if(cntx[i]!=cnty[i])p[++j]=p[i],cntx[j]=cntx[i],cnty[j]=cnty[i];if(i==m)m=j;}for(int i=1,sum;i<=n;i++){if(a[i]%x)continue;sum=0;for(int j=1,s=a[i],cnt;j<=m;j++){cnt=0;while(s%p[j]==0)cnt++,s/=p[j];if(cnt>cntx[j])sum+=(1<<(j-1));}minn[sum]++;}for(int i=1,sum;i<=n;i++){if(y%a[i])continue;sum=0;for(int j=1,s=a[i],cnt;j<=m;j++){cnt=0;while(s%p[j]==0)cnt++,s/=p[j];if(cnt<cnty[j])sum+=(1<<(j-1));}maxn[sum]++;}for(int i=0;i<m;i++)for(int j=0;j<(1<<m);j++)if((j>>i)&1)maxn[j]+=maxn[j-(1<<i)];for(int i=0;i<(1<<m);i++)ans+=minn[i]*maxn[(1<<m)-1-i];printf("%lld\n",ans);}return 0;
}