URAL 1091 Tmutarakan Exams

题意

N 以内的大小为 K 的数集个数,满足数集内的数的 gcd>1

题解

设f[x]表示公约数是x的倍数的情况数,g[x]表示公约数恰好是x的情况数
有:
fn=n|dg(d)
gn=n|df(d)μ(dn)
其中 fn=(Ndk)

gn=2nNn|d(Ndk)μ(dn)

交换后
gn=d(Ndk)n|dμ(dn)[n2]

注意到二项式系数当 dN 时为 0 ,故
gn=1dN(Ndk)([n==1]μ(d))


gn=2dN(Ndk)

code

#include<cstdio>
#include<cstring>

typedef long long LL;

const int maxn=1010;
const int maxp=1010;

int prime[maxp],primeN;
int phi[maxn], mu[maxn];
LL sphi[maxn];int smu[maxn];
bool isprime[maxn];
void gen(int n) {
    primeN = 0;
    memset(isprime, 1, sizeof isprime);

    isprime[0]=isprime[1]=0;
    phi[1]=1, mu[1]=1;
    for(int i=2,p;i<n;++i){
        if (isprime[i]) {
            prime[primeN ++]=p=i;
            phi[p]=p-1, mu[p]=-1;
        }

        for(int j=0,x;j<primeN && (x=i*(p=prime[j]))<n;++j){
            isprime[x] = 0;

            if(!(i%p)){
                phi[x]=phi[i]*p, mu[x]=0;
                break;
            } else {
                phi[x]=phi[i]*(p-1), mu[x]=-mu[i];
            }
        }
    }
}

const int MAXN=60;
int K,N;
LL C[MAXN][MAXN];

int main(){
//  freopen("in.txt","r",stdin);
    scanf("%d%d",&K,&N);

    gen(N+1);
    for(int i=0;i<=N;++i){
        C[i][0]=C[i][i]=1;
        for(int j=1;j<i;++j)
            C[i][j]=C[i-1][j]+C[i-1][j-1];
    }

    LL res=0;

    for(int d=1;d<=N;++d)
        res+=C[N/d][K]*((d==1) - mu[d]);

/*  for(int n=2;n<=N;++n)
        for(int d=n;d<=N;++d)if(d%n==0)
            res+=C[N/d][K]*mu[d/n];
*/  
    printf("%d\n",res<=10000 ? res : 10000);
//  for(;;);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yeziqing10/article/details/50660075
今日推荐