给出 n n n个数,求有多少对 i , j , k i,j,k i,j,k满足
i < j < k i
发现 p p p最大只有 1 0 6 10^6 106
那么 p p p最多只有 2 8 2^8 28即 256 256 256个因数
那么我们可以先将 p p p的因数求出来
另外,显然的是一个数 a i a_i ai对答案有贡献的只有 g c d ( a i , p ) gcd(a_i,p) gcd(ai,p)
那么我们可以用一个桶来记录 g c d ( x , p ) gcd(x,p) gcd(x,p)有多少个
暴力枚举3个 p p p的因数,注意可以相同
分类讨论:
设 i , j , k i,j,k i,j,k表示三个因数
若 i ∗ j ∗ k i*j*k i∗j∗k不是 p p p的倍数或者有任意一个因数不在桶内,直接跳过
正确性自己推
#include
using namespace std;
int n,p,i,j,k,tot,x;
int c[300],tub[1000005];
long long ans;
int gcd(int x,int y)
{
int r=x%y;
while (r!=0)
{
x=y;
y=r;
r=x%y;
}
return y;
}
int main()
{
freopen("divide.in","r",stdin);
freopen("divide.out","w",stdout);
scanf("%d%d",&n,&p);
for (i=1;i<=n;i++)
{
scanf("%d",&x);
tub[gcd(x,p)]++;
}
for (i=1;i<=p;i++)
{
if (p%i==0)
{
tot++;
c[tot]=i;
}
}
for (i=1;i<=tot;i++)
{
if (tub[c[i]]==0) continue;
for (j=i;j<=tot;j++)
{
if (tub[c[j]]==0) continue;
for (k=j;k<=tot;k++)
{
if (tub[c[k]]==0) continue;
if ((long long)c[i]*c[j]*c[k]%p!=0) continue;
if (i==j&&j==k) ans+=tub[c[i]]*(tub[c[i]]-1)*(tub[c[i]]-2)/6;
else if (i==j||i==k) ans+=(tub[c[i]]-1)*tub[c[j]]*tub[c[k]]/2;
else if (j==k) ans+=tub[c[i]]*(tub[c[j]]-1)*tub[c[k]]/2;
else ans+=tub[c[i]]*tub[c[j]]*tub[c[k]];
}
}
}
printf("%lld\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}