URAL

题意:K个不同数组成的集合,每个数都不超过S且它们的gcd>1。求这样的数的个数
分析:从2开始枚举gcd,但这样会发生重复。譬如,枚举gcd=2的集合个数和gcd=3的集合个数,枚举6的时候就重复了,所以对于6,10这种质因子个数为2的,要减去。而对于4,8,9这样同一质因子出现超过1次的,不用考虑(相当于莫比乌斯函数值为0)。
因为K和S不大,先预处理出组合数以及每个数对应的质因子个数。然后按容斥计算答案。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 55;
int C[maxn][maxn];
int cnt[maxn];
bool isprime(int n)
{
    if(n<2) return false;
    for(int i=2;i*i<=n;++i){
        if(n%i==0) return false;
    }
    return true;
}
void pre()
{
    for(int i=2;i<maxn;++i){
        if(isprime(i)){
            cnt[i]=1;
        }else{
            int tmp = i;
            for(int j=2;j*j<=tmp;++j){
                if(tmp%j==0){
                    int t = 0;
                    while(tmp%j==0) tmp/=j,t++;
                    if(t>1){                                //莫比乌斯函数值为0,不必考虑
                        cnt[i] = 0;
                        break;
                    }
                    cnt[i]++;
                }
            }
            if(cnt[i]==0) continue;
            if(tmp>1) cnt[i]++;
        }
    }
    
    C[1][0] = C[1][1] = 1;
    for(int i=2;i<maxn;++i){
        C[i][0] = 1;
        for(int j=1;j<=i;++j){
            C[i][j] = C[i-1][j]+C[i-1][j-1];
        }
    }
}

int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    pre();
    int K,S; 
    while(scanf("%d %d",&K, &S)==2){            //枚举公约数
        int res=0;
        for(int i=2;i<=S;++i){
            if(!cnt[i]) continue;
            int num = S/i;
            int tmp = C[num][K];
            if(cnt[i]&1) res += tmp;
            else res -= tmp;
        }
        if(res>10000) res=10000;
        printf("%d
",res);
    }
    return 0;
}
为了更好的明天
原文地址:https://www.cnblogs.com/xiuwenli/p/9695091.html