ABC195 F-Coprime Present (gcd nature, state pressure dp)

Title:

Insert picture description here

solution:

设两个数x和y都是[A,B]内的数,且x>y,
存在结论:
当x和y不互质时,gcd(x,y)<=x-y(证明放在最下面),
而x-y<=B-A<=72,因此gcd一定在[1,72].

[1,72]72个数,但我们只需要判断是否互质,
那么我们只需要判断x和y是否同时拥有[2,72]中的某个质因子即可.
[1,72]的质因子数量只有20.

[A,B]中的每个数都可以用一个20位的二进制数表示其[1,72]内的质因子,
然后就可以状压dp了:
为了保证互质,选出的数的集合中,每种质因子最多只能出现一次,
令d[i][j]表示前i个数,质因子集合为j的方案数,
然后问题就变为一个比较基础的状压dp了.
证明当x和y不互质时,gcd(x,y)<=x-y:
设x>y,且x和y的gcd为t,那么x和y都是t的倍数,
设x=k1*t,y=k2*t,那么x和y的差值为(k1-k2)*t=x-y,
移项得t=(x-y)/(k1-k2),由x>y可知(k1-k2)>=1,
因此t<=x-y.

code:

#include <bits/stdc++.h>
#define int long long
#define PI pair<int,int>
using namespace std;
const int maxm=2e5+5;
int d[77][(1<<20)];
int p[maxm],c;
int st[77];
int A,B;
bool isprime(int x){
    
    
    for(int i=2;i*i<=x;i++){
    
    
        if(x%i==0)return 0;
    }
    return 1;
}
void init(){
    
    
    for(int i=2;i<=72;i++){
    
    
        if(isprime(i)){
    
    
            p[c++]=i;
        }
    }
}
void solve(){
    
    
    init();
    cin>>A>>B;
    int n=0;
    for(int i=A;i<=B;i++){
    
    //预处理[A,B]中每个数包含的质因子.
        for(int j=0;j<c;j++){
    
    
            if(i%p[j]==0){
    
    
                st[n]|=(1<<j);
            }
        }
        n++;
    }
    d[0][0]=1;
    for(int i=0;i<n;i++){
    
    
        for(int j=0;j<(1<<c);j++){
    
    
            if(!d[i][j])continue;
            d[i+1][j]+=d[i][j];//不选st[i]
            if(!(j&st[i])){
    
    //选st[i]
                d[i+1][j|st[i]]+=d[i][j];
            }
        }
    }
    int ans=0;
    for(int j=0;j<(1<<c);j++){
    
    
        ans+=d[n][j];
    }
    cout<<ans<<endl;
}
signed main(){
    
    
    ios::sync_with_stdio(0);
    solve();
    return 0;
}

Guess you like

Origin blog.csdn.net/weixin_44178736/article/details/114937935