ABC195 F

题意

求出由 ([A,B]) 内数字组成的内部数字两两互质的集合的个数。((1≤A≤B≤10^{18}))题目链接:https://atcoder.jp/contests/abc195/tasks/abc195_f

分析

首先,根据辗转相除法,有 (gcd(a,b)=gcd(a-b,b)(ageq b)),因此这些数字的 (gcd) 的范围不会超过 (72),只需要对这些质数进行讨论就可以判断两个数是否互质。

因为 (72)以内的质数只有 (20) 个,因此可以通过状态压缩来表示每个数含有的质数的情况。当两个状态相与结果为 (0) ,表示二者互质。dp[i] 表示 i 对应的集合个数。

代码

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N=(1<<20);
bool vis[80];
int prime[25],cnt;
ll dp[N];
void init(){
    int maxn=72;
    cnt=0;
    for(int i=2;i<=maxn;i++){
        if(!vis[i])
            prime[++cnt]=i;
        for(int j=1;j<=cnt&&prime[j]*i<=maxn;j++){
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
                break;
        }
    }
}
int main(){
    init();
    ll a,b;
    scanf("%lld%lld",&a,&b);
    dp[0]=1;//空集
    for(ll i=a;i<=b;i++){
        int msk=0;
        for(int j=1;j<=cnt;j++){//得到i含有的质因子
            if(i%prime[j]==0)
                msk|=(1<<(j-1));
        }
        for(int j=0;j<(1<<cnt);j++){
            if(!(msk&j))//表示两个状态互质
                dp[msk|j]+=dp[j];
        }
    }
    ll ans=0;
    for(int i=0;i<(1<<cnt);i++) 
        ans+=dp[i];
    printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/1024-xzx/p/14545380.html