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|种情况。

hdu 3908 Triple ——容斥_第1张图片

设实线表示互素,虚线表示不互素,那么一组互素(右图)或者两组互素(左图)
的三元组,可以表示成上面两图的形式。
对于上面左图这一类三元组,在枚举 B 和枚举 C 的时候,都会被统计,一共被统计
了两次;同理,对于上面右图这一类三元组,在枚举 B 和枚举 C 的时候,也都会被
统计,一共被统计了两次。这两种三元组都会被统计两次,最后要除以 2。
上代码:
2011-08-03  19:17:52  Accepted  3908 531MS 2724K  829 B G++  LadyTutu
#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);
}
}

  

你可能感兴趣的:(HDU)