• 51nod1439 互质对 [莫比乌斯函数, 容斥]


    互质对

    有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,里面有一对互质


    color{blue}{最初想法}

    考虑每次 /加入/删除 一个数字对答案的影响,

    将数字 xx 分解质因数, 发现可以通过把质因子记录在 桶 内快速得知数 xx 与集合中哪些质因子重复, 但是不知道质因子具体属于哪些数 .


    color{red}{正解部分}

    分解质因子 ightarrow 分解因子 =AC=AC , 一步之遥= =

    现在的目标是: xx 与集合内的多少数字互质 .
    x=p1p2...pmx = p_1*p_2*...*p_m, (指数懒得打了…),

    分解因子后存到对应的桶 cnt[]cnt[] 里,

    num=totcnt[p1]cnt[p2]...+cnt[p1p2]+......+...num_{互质}=tot - cnt[p_1]-cnt[p_2]-...+cnt[p_1*p_2]+...-...+... .

    容斥系数为 莫比乌斯函数, 没学过的可以看 这里 .


    color{red}{实现部分}

    像这种数组下标和值容易混淆的题目, 要注意区分 …

    #include<cstdio>
    #include<cstring>
    typedef long long ll;
    #define reg register
    
    //{{{ define
    const int maxn = 5e5 + 10;
    
    int N;
    int Q;
    int p_cnt;
    int A[maxn];
    int p[maxn];
    int mu[maxn];
    bool Used[maxn];
    
    ll Ans;
    ll cnt[maxn];
    //}}}
    
    
    void sieve(){
            mu[1] = 1;
            for(reg int i = 2; i < maxn; i ++){
                    if(!Used[i]) p[++ p_cnt] = i, mu[i] = -1;
                    for(reg int j = 1, t; j <= p_cnt && (t = p[j]*i) < maxn; j ++){
                            Used[t] = 1;
                            if(i % p[j] == 0){ mu[t] = 0; break ; };
                            mu[t] = -mu[i];
                    }
            }
    } //
    
    void Add(int x){
            for(reg int d = 1; d*d <= x; d ++){
                    if(x % d) continue ;
                    Ans += mu[d] * (cnt[d] ++);
                    int d2 = x / d;
                    if(d != d2) Ans += mu[d2] * (cnt[d2] ++);
            }
    }
    
    void Del(int x){
            for(reg int d = 1; d*d <= x; d ++){
                    if(x % d) continue ;
                    Ans -= mu[d] * (-- cnt[d]);
                    int d2 = x / d;
                    if(d != d2) Ans -= mu[d2] * (-- cnt[d2]);
            }
    }
    
    void Work(){
            int x;
            scanf("%d", &x);
            !Used[x]?Add(A[x]):Del(A[x]);
            Used[x] ^= 1;
            printf("%lld
    ", Ans);
    }
    
    int main(){
            scanf("%d%d", &N, &Q);
            for(reg int i = 1; i <= N; i ++) scanf("%d", &A[i]);
            sieve(); memset(Used, 0, sizeof Used);
            while(Q --) Work();
            return 0;
    }
    
    
  • 相关阅读:
    让vs2013自带的IISExpress支持apk文件下载
    使用h5开发跨平台APP确保数据安全交互---服务器篇
    如何使用iis发布多个ftp,为何ftp 503错误?
    HttpApplication执行顺序
    EXCEL2010分成多个窗口的,解决单个窗口显示多个文档的弊病
    搜索引擎优化(SEO)解决方案
    .net网站快速停机设置app_offline
    SQL SERVER 连接 SQL SERVER 连接服务器
    SQL SERVER 备份还原 局域网 远程
    postgres 临时表
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822538.html
Copyright © 2020-2023  润新知