51 nod 1439 互质对(Moblus容斥)

Posted Przz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51 nod 1439 互质对(Moblus容斥)相关的知识,希望对你有一定的参考价值。

1439 互质对技术分享

题目来源: CodeForces
基准时间限制:2 秒 空间限制:131072 KB 分值: 160 难度:6级算法题

有n个数字,a[1],a[2],…,a[n]。有一个集合,刚开始集合为空。然后有一种操作每次向集合中加入一个数字或者删除一个数字。每次操作给出一个下标x(1 ≤ x ≤ n),如果a[x]已经在集合中,那么就删除a[x],否则就加入a[x]。

问每次操作之后集合中互质的数字有多少对。

注意,集合中可以有重复的数字,两个数字不同当且仅当他们的下标不同。

比如a[1]=a[2]=1。那么经过两次操作1,2之后,集合之后存在两个1,里面有一对互质。

Input
单组测试数据。
第一行包含两个整数n 和 q (1 ≤ n, q ≤ 2 × 10^5)。表示数字的种类和查询数目。
第二行有n个以空格分开的整数a[1],a[2],…,a[n] (1 ≤ a[i] ≤ 5 × 10^5),分别表示n个数字。
接下来q行,每行一个整数x(1 ≤ x ≤ n),表示每次操作的下标。
Output
对于每一个查询,输出当前集合中互质的数字有多少对。
Input示例
样例输入1
5 6
1 2 3 4 6
1
2
3
4
5
1
样例输入2
2 3
1 1
1
2
1
Output示例
样例输出1
0
1
3
5
6
2
样例输出2
0
1
0

 

/*
51 nod 1439 互质对(Moblus容斥)

problem:
有n个数字,a[1],a[2],…,a[n]。有一个集合,刚开始集合为空。然后有一种操作每次向集合中加入一个数字或者删除一个数字。
每次操作给出一个下标x,如果a[x]已经在集合中,那么就删除a[x],否则就加入a[x]。
问每次操作之后集合中互质的数字有多少对。
注意,集合中可以有重复的数字,两个数字不同当且仅当他们的下标不同。
比如a[1]=a[2]=1。那么经过两次操作1,2之后,集合之后存在两个1,里面有一对互质。

solve:
问题可以看成每次添加后,增加or减少的这个数与集合中数互质的个数.
于是就成了求一个数与一个集合中互质数的个数. 用数组来记录集合中数的约数情况
然后再利用容斥原理(Moblus实现的). 就能求出GCD为1的个数

hhh-2016/10/01-22:28:16
*/
#pragma comment(linker,"/STACK:124000000,124000000")
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#include <queue>
#include <functional>
#include <math.h>
#define lson  i<<1
#define rson  i<<1|1
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
#define key_val ch[ch[root][1]][0]
using namespace std;
const int maxn = 5e5 + 1000;
const int inf = 0x3f3f3f3f;
const ll mod = 1000000007;
const double eps = 1e-7;
template<class T> void read(T&num)
{
    char CH;
    bool F=false;
    for(CH=getchar(); CH<‘0‘||CH>‘9‘; F= CH==‘-‘,CH=getchar());
    for(num=0; CH>=‘0‘&&CH<=‘9‘; num=num*10+CH-‘0‘,CH=getchar());
    F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p)
{
    if(!p)
    {
        puts("0");
        return;
    }
    while(p) stk[++ tp] = p%10, p/=10;
    while(tp) putchar(stk[tp--] + ‘0‘);
    putchar(‘\n‘);
}
int tot;
int is_prime[maxn];
ll mu[maxn];
int prime[maxn];

void Moblus()
{
    tot = 0;
    mu[1] = 1;
    memset(is_prime,0,sizeof(is_prime));
    for(int i = 2; i < maxn-10; i++)
    {
        if(!is_prime[i])
        {
            prime[tot++] = i;
            mu[i] = -1;
        }

        for(int j = 0; j < tot && i*prime[j] < maxn-10; j++)
        {
            is_prime[i*prime[j]] = 1;
            if(i % prime[j])
            {
                mu[i*prime[j]] = -mu[i];
            }
            else
            {
                mu[i*prime[j]] = 0;
                break;
            }
        }
    }
}


int vis[maxn];
int hav[maxn];
int a[maxn];
int main()
{
    Moblus();
    int num = 0;
    int n,m;
    read(n),read(m);
    for(int i =1 ;i <= n;i++)
        read(a[i]);
    ll ans = 0;
    int x;
    for(int i =1 ;i <= m;i++)
    {
        ll tans = 0;
        read(x);
        int t = 1;
        if(vis[x])
            t = -1;
        for(int j = 1;j * j <= a[x];j ++)
        {
            if(a[x]%j)
                continue;
            tans += (ll)mu[j] * hav[j];
            hav[j] += t;

            if(j * j != a[x]){
                tans += (ll)mu[a[x]/j] * hav[a[x]/j];
                hav[a[x]/j] += t;
            }
        }
        vis[x]+=t;
        num += t;
        ans += (ll)tans*t;
        if(a[x] == 1 && vis[x] == 0)
            ans += 1LL;
        printf("%I64d\n",ans);
    }
    return 0;
}

  

以上是关于51 nod 1439 互质对(Moblus容斥)的主要内容,如果未能解决你的问题,请参考以下文章

51 nod 1610 路径计数(Moblus+dp)

1439 互质对

51Nod1317 相似字符串对 容斥原理 动态规划

51nod 1317 相似字符串对(容斥原理+思维)

51Nod 1419 最小公倍数挑战

做题51NOD1518 稳定多米诺覆盖——容斥&dp