SPOJ:NO GCD (求集合&秒啊)

Posted ---学习ing---

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPOJ:NO GCD (求集合&秒啊)相关的知识,希望对你有一定的参考价值。

You are given N(1<=N<=100000) integers. Each integer is square free(meaning it has no divisor which is a square number except 1) and all the prime factors are less than 50. You have to find out the number of pairs are there such that their gcd is 1 or a prime number. Note that (i,j) and (j,i) are different pairs if i and j are different.

 

Input

The first line contains an integer T(1<=T<=10) , the number of tests. Then T tests follows. First line of each tests contain an integer N. The next line follows N integers.

 

Output

Print T lines. In each line print the required result.

 

Sample Input

Sample Output

1

3

2 1 6 

 

Explanation

gcd(1,2)=1

gcd(2,1)=1

gcd(2,6)=2, a prime number

gcd(6,2)=2, a prime number

gcd(1,6)=1

gcd(6,1)=1

gcd(2,2)=2, a prime number

gcd(1,1)=1

So, total of 8 pairs.

 

题意:给定数组a[],求多少对(i,j),使得a[i],a[j]互质或者gcd是质数,保证a[]只有小于50的素因子,而且不含平方因子。

思路:注意到只有15个素数,开始想到了用二进制来找互质的个数和有一个素因子的个数,但是复杂度好像还是过不去。第二天忍不住参考了vj上面的代码。。。

主要问题在于,如何快速地求一个二进制的子集,即对i,求所有的j,j<=i&&(i|j)==i。后面地就不难。

前辈写的是:

    for(i=0;i<M;i++){
            for(j=i;;j=(j-1)&i){        
               s[i]+=num[j]; //关键,得到子集 
               if(!j) break;
            }
        }

。。。注意把0也要累加进去。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int M=1<<15;
int num[M],s[M];
int p[15]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
int main()
{
    int T,N,i,j,tmp; ll ans,x;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&N);
        memset(num,0,sizeof(num));
        memset(s,0,sizeof(s));
        for(i=1;i<=N;i++){
           scanf("%lld",&x); tmp=0;
           for(j=0;j<15;j++) if(x%p[j]==0) tmp+=1<<j;
           num[tmp]++;
        }
        for(i=0;i<M;i++){
            for(j=i;;j=(j-1)&i){        
               s[i]+=num[j]; //关键,得到子集 
               if(!j) break;
            }
        } ans=0;
        for(i=0;i<M;i++){
            ans+=(ll)num[i]*s[i^(M-1)];//互质 
            for(j=0;j<15;j++){ //刚好有一个素因子
                if(i&1<<j){
                    ans+=(ll)num[i]*(s[i^(M-1)^(1<<j)]-s[i^(M-1)]);//减法保证这个素因子不被减去 
                } 
            } 
        }
        cout<<ans<<endl; 
    }
    return 0;
}

 

以上是关于SPOJ:NO GCD (求集合&秒啊)的主要内容,如果未能解决你的问题,请参考以下文章

题解 P4139 上帝与集合的正确用法

数论——gcd&&lcm

UVA 11426 (欧拉函数&&递推)

POJ 3592--Instantaneous TransferenceSCC缩点新建图 &amp;&amp; SPFA求最长路 &amp;&amp; 经典(示例代(代

数论集合

数论集合