URAL1091:Tmutarakan Exams(容斥 & 莫比乌斯反演)

本文介绍了一个关于从特定范围内选取多个数,使这些数的最大公约数大于1的问题,并提供了两种解决该问题的代码实现思路。一种是利用莫比乌斯函数进行容斥原理的应用,另一种则是通过倒序枚举最大公约数并直接减去其倍数的方法。
摘要由CSDN通过智能技术生成

1091. Tmutarakan Exams

Time limit: 1.0 second
Memory limit: 64 MB
University of New Tmutarakan trains the first-class specialists in mental arithmetic. To enter the University you should master arithmetic perfectly. One of the entrance exams at the Divisibility Department is the following. Examinees are asked to find  K different numbers that have a common divisor greater than 1. All numbers in each set should not exceed a given number  S. The numbers  K and  S are announced at the beginning of the exam. To exclude copying (the Department is the most prestigious in the town!) each set of numbers is credited only once (to the person who submitted it first).
Last year these numbers were  K=25 and  S=49 and, unfortunately, nobody passed the exam. Moreover, it was proved later by the best minds of the Department that there do not exist sets of numbers with the required properties. To avoid embarrassment this year, the dean asked for your help. You should find the number of sets of  K different numbers, each of the numbers not exceeding  S, which have a common divisor greater than 1. Of course, the number of such sets equals the maximal possible number of new students of the Department.

Input

The input contains numbers  K and  S (2 ≤  K ≤  S ≤ 50).

Output

You should output the maximal possible number of the Department's new students if this number does not exceed 10000 which is the maximal capacity of the Department, otherwise you should output 10000.

Sample

input output
3 10
11
题意:从1~s中选择k个不同的数,使得他们最大公因数不等于1,问方案总数。

思路:枚举gcd一般有两种思路,一是利用莫比乌斯函数进行容斥,二是倒着枚举gcd,直接减去它的倍数。

# include <iostream>
# include <cstdio>
# include <cstring>
using namespace std;
typedef long long LL;
const int maxn = 50;
short mu[maxn+3];
bool bo[maxn+3];
int prime[maxn+3];
LL c[28][28];
int k, s;
void init()
{
    for(int i = 0; i <= 25; i++)   c[i][0] = 1;
    for(int i = 1; i <= 25; i++)
        for(int j = 1; j <= 25; j++)
            c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
}
void get_table()
{
    mu[1] = 1;
    memset(bo, 0, sizeof(bo));
    for(int i=2; i<=maxn; ++i)
    {
        if(!bo[i])
        {
            prime[++prime[0]] = i;
            mu[i] = -1;
        }
        for(int j=1; j<=prime[0] && i*prime[j]<=maxn; ++j)
        {
            bo[i*prime[j]] = 1;
            if(i%prime[j]==0)
            {
                mu[i*prime[j]] = 0;
                break;
            }
            else
                mu[i*prime[j]] = -mu[i];
        }
    }
}
int main()
{
    init();
    get_table();
    scanf("%d%d",&k,&s);
    LL ans = 0;
    for(int i=2; i<=s; ++i)
        for(int j=i; j<=s; j+=i)
            ans += c[s/j][k]*mu[j/i];
    if(ans > 10000) ans = 10000;
    printf("%lld\n",ans);
    return 0;
}

# include <iostream>
# include <cstdio>
# include <cstring>
using namespace std;
typedef long long LL;
const int maxn = 50;
LL c[28][28], sum[53];
int k, s;
void init()
{
    for(int i = 0; i <= 25; i++)   c[i][0] = 1;
    for(int i = 1; i <= 25; i++)
        for(int j = 1; j <= 25; j++)
            c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
}
int main()
{
    init();
    scanf("%d%d",&k,&s);
    LL ans = 0;
    for(int i=s; i>1; --i)
    {
        LL tmp = c[s/i][k];
        for(int j=i+i; j<=s; j+=i)
            tmp -= sum[j];
        sum[i] = tmp;
        ans += tmp;
    }
    if(ans > 10000) ans = 10000;
    printf("%lld\n",ans);
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值