首页 > 其他分享 >AtCoder-abc230_g GCD Permutation 容斥

AtCoder-abc230_g GCD Permutation 容斥

时间:2022-12-28 21:34:49浏览次数:62  
标签:AtCoder gcd int 容斥 因子 倍数 Permutation GCD

J - GCD Permutation

传送门J - GCD Permutation

知识点:素数筛、容斥定理、gcd

题意:长度为n的一个排列a中,求满足\(gcd(i,j)!=1 且 gcd(a_i,a_j)!=1\)的i,j对数。i,j可以相同。n<=2e5

解法

根据埃氏筛的原理,我们知道1到n的所有倍数的总数是O(n)级别的。因此,我们可以2到n枚举作为因子的k,那么他的所有倍数两两不互质。显然这种方法枚举出来的数字总数是O(n)级别。

得到了k的倍数后,已经解决了gcd(i,j)!=1的条件。如果对这些倍数位置上的数字两两判断gcd的话一定会超时,因为单单是2的倍数就有1e5,不可以跑\(n^2\)的写法。

那么我们就要快速解决在k倍位置上有多少对贡献。两个数不互质是一定有共同的因子,可以把每个数的因子分离出来,分别计数,用map存储。

如果分离出来了x个2,y个3,z个6,那么以2作为公共因子的有x(x-1)/2对,以3作为公共因子的有y(y-1)/2对。分别计入答案之后发现2,3作为因子的贡献中,6作为因子的贡献重复了,所以还要减去6的贡献z(z-1)。

以此类推,这个问题就要用容斥来解决了。质因子数量是奇数的数字加入答案,是偶数的数字从答案扣除。含有同一质因子多次的的数字跳过。因为我们先统计了质因子的答案,然后要去掉含两个不同质因子的答案,加回来含三个不同质因子的答案。。。

这样我们就解决了k为i,j因子的贡献,同理,k=2与k=3会重复计算k=6部分的贡献,所以也要再跑一边容斥。

这样跑完得到的是不含i,j相同情况的答案,再扫一遍就行了。

#include <bits/stdc++.h>
using namespace std;
#define yaqujiejie yyds
typedef long long ll;
#define int long long
const int N = 2e5+10;
vector<int>prime;//存储素数
vector<int>yz[N];//因子
vector<int>bs[N];//倍数
bool nop[N];//不是素数
bool no[N];//不可
int yzs[N];//质因数数量
void init(){
    for(int i=2;i<N;i++){
        if(!nop[i]){
            if(i*i<N&&i*i>0)no[i*i]=1;
            prime.push_back(i);
            yzs[i]++;
            for(int j=i*2;j<N;j+=i){
                nop[j]=1;
                yzs[j]++;
                ll k=(ll)i*i;
                if(j%k==0)no[j]=1;
            }
        }
        yz[i].push_back(i);
        bs[i].push_back(i);
        for(int j=i*2;j<N;j+=i){
            yz[j].push_back(i);
            bs[i].push_back(j);
        }
    }
}
int a[N];
signed main(){
    ios::sync_with_stdio(false);
    init();
    int n;cin>>n;
    ll ans=0;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int k=2;k<=n;k++){
        unordered_map<int,int>mp;
        for(int j=0;j<bs[k].size();j++){
            for(int u=0;u<yz[a[bs[k][j]]].size();u++){
                mp[yz[a[bs[k][j]]][u]]++;
            }
        }
        ll res=0;
        for(auto p:mp){
            if(no[p.first])continue;
            
            if(yzs[p.first]%2==1)res+=p.second*(p.second-1)/2;
            else res-=p.second*(p.second-1)/2;
        }
        if(no[k])continue;
        if(yzs[k]%2==1)ans+=res;
        else ans-=res;
    }
    for(int i=2;i<=n;i++)if(a[i]!=1)ans++;
    cout<<ans<<"\n";
}

标签:AtCoder,gcd,int,容斥,因子,倍数,Permutation,GCD
From: https://www.cnblogs.com/wtn135687/p/17011316.html

相关文章

  • AtCoder Beginner Contest 239总结
    由于比赛延期了一个星期,今天才打,恰巧我记错了时间,本来是8:00,我记成9:00,然后·········幸运的是我还是把前四题做出来了(intwentyminutes),由于时间问题,我......
  • Atcoder Beginner Contest 244总结
    这次的Rating凉了………………这次出乎T3意料的考了交互题,虽然很简单,但卡了我好久……T4考了一个神奇的东西,我用骗分大法水了过去……一看排名发现有快3000人得了1000分......
  • Atcoder Beginner Contest 242
    由于我8点半才下课,我只好晚半个小时再打,这次还行,排名3042五道题,秒了前三道,第四道不会,第五道想出正解,结果一直不对,比完后看了一下大佬的代码恍然大悟,但是比赛早已结束...........
  • AtCoder Beginner Contest 283
    《E-Don'tIsolateElements》dp   刚开始拿到这道题时,我总是在想:第一行翻不翻转对下面情况的影响,在什么情况下要反转,等一系列情况最后我发现:这些情况不如我可......
  • 容斥原理
    \(\mathcalPreface\)可能容斥原理的公式等还是\(AK\IOI\)的巨佬讲得详细,大家可以看看这篇博客。这篇博客把我写得手废了。我这个里这接上公式:\[|\bigcup\limits_{i......
  • Atcoder Beginner Contest ABC 283 Ex Popcount Sum 题解 (类欧几里得算法)
    题目链接令\(p=\lfloor\frac{n-r}m\rfloor\),则我们其实是要对所有\(0\lei\le29\)求\(\sum_{j=0}^p(\lfloor\frac{mj+r}{2^i}\rfloormod\2)\)。右边那个东西如果没......
  • AtCoder Grand Contest 060(持续更新)
    Preface那一天,闪总终于想起了被ACG支配的恐惧……只能说还好Rating不够,这场Unrated打的,写了个A然后B一直挂(一个细节没想到),C数数又数不来90min后光速跑路推Gal去了A-......
  • CF213E Two Permutations
    好久没有交流题目了啊,回来补一下之前的哈。题目要使 $a_1+x$,$a_2+x$,$\cdots$,$a_n+x$是$b$序列的子序列。这里最烦的部分应该就是子序列是不连续的。注意到$a$序列......
  • AtCoder Beginner Contest 283(A~F)
    Aa,b=map(int,input().split())print(pow(a,b))Bn=int(input())a=list(map(int,input().split()))q=int(input())foriinrange(q):op=list(map(int,input()......
  • 「杂题乱写」AtCoderDP26 题
    「杂题乱写」AtCoderDP26题\(\text{AtCoderDP26}\)题题单。前言最近听说\(\text{AtCoder}\)上有个\(\text{DP26}\)题挺好的,于是向@\(\text{SoyTony}\)要了题单......