hdu 3908 Triple ——容斥
多校又被虐惨了…… 这个题下来写了一下 就是因为没有加memset和去掉freopen wa了几次……
官方题解:
直接暴力枚举 O(N^3*GCD)会超时。
可以先计算出有一组互素或者两组互素的所有三元组个数 sum,最后把所有三元组
的个数减去 sum。
计算 a 可以做到 O(N^2*GCD)。
可以这样来求一组互素或者两组互素的三元组:
对于每个数 Ai,设与 Ai 互素的数在集合 Ni 中,与 Ai 不互素的数在集合 Mi 中,这
样 Ai 和 Ni 中的一个数以及 Mi 中的一个数构成了“一组互素或者两组互素”这种情
况,一共有|Ni|*|Mi|种情况。

设实线表示互素,虚线表示不互素,那么一组互素(右图)或者两组互素(左图)
的三元组,可以表示成上面两图的形式。
对于上面左图这一类三元组,在枚举 B 和枚举 C 的时候,都会被统计,一共被统计
了两次;同理,对于上面右图这一类三元组,在枚举 B 和枚举 C 的时候,也都会被
统计,一共被统计了两次。这两种三元组都会被统计两次,最后要除以 2。
上代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
int tri[810];
int map[810][810];
int gcd(int a,int b)
{
if(b==0)
return a;
else return gcd(b,a%b);
}
int main(void)
{
//freopen("data.in","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
memset(tri,0,sizeof(tri));
memset(map,0,sizeof(map));
int n;
scanf("%d",&n);
int i;
for(i=1;i<=n;i++)
{
scanf("%d",&tri[i]);
}
int j;
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
{
if(i!=j)
{
//coprime 1
if(gcd(tri[i],tri[j])==1)
map[i][j]=map[j][i]=1;
}
}
int sum=0,tot=0;
for(i=1;i<=n;i++)
{
tot=0;
for(j=1;j<=n;j++)
{
tot+=map[i][j];
}
sum+=tot*(n-1-tot)/2;
}
printf("%d\n",n*(n-1)*(n-2)/6-sum);
}
}
浙公网安备 33010602011771号