codeforces #305 547C C. Mike and Foam(莫比乌斯反演)

题目链接:

点击打开链接

题目大意:

给出一列数,最开始集合 为空,然后q次操作,每次给出一个x,如果第x个数存在,那么删去,不存在添加,问操作完互质的数有多少对

题目分析:

问互质的数的对数,裸裸的数论题

首先f(k)定义为gcd(ai,aj)(1<=i

定义F(k)为k|gcd(ai,aj)(1<=i

那么根据莫比乌斯反演定理的第二种形式得到f(k) = sigma(d>=1)[u(d)*F(d*k)]

定义cnt[i]为集合中是i的倍数的数有多少个

那么F(k) = C(2 , cnt[k] ) 结论很显然

所以我们可以利用莫比乌斯反演,在每次根据要添加或删除的数修正结果,然后输出即可

也就是对给出的数分解质因数,然后因为如果当前数含有某个质因数的2次方及以上,u等于0

而且因为2*3........*17 > 500000,所以质因数的个数不会超过6个,只要枚举2^6种影响到的F(k)即可

总的复杂度q*2^6,绝对的秒出

#include 
#include 
#include 
#include 
#include 
#define MAX 500007

using namespace std;

typedef long long LL;

int n,q,x;
int a[MAX];
int u[MAX];
int used[MAX];
int cnt[MAX];
int maxPrime[MAX];
vector v;

LL ans;

void init ( )
{
    memset ( maxPrime , -1 , sizeof ( maxPrime ) );
    for ( int i = 1 ; i < MAX ; i++ ) u[i] = 1;
    for ( int i = 2 ; i < MAX ; i++ )
    {
        if ( ~maxPrime[i] ) continue;
        for ( int j = 1 , t = i ; t < MAX ; j++,t += i )
        {
            maxPrime[t] = i;
            u[t] = j%i==0?0:-u[t];
        }
    }   
}

void update ( int x , int f )
{
    v.clear();
    while ( x > 1 )
    {
        int p = maxPrime[x];
        v.push_back(p);
        while ( x%p == 0 )
            x /= p;
    }
    int m = v.size();
    int total = 1<


你可能感兴趣的:(codeforces #305 547C C. Mike and Foam(莫比乌斯反演))