NEUOJ: 1299: 磊磊的难题

1299: 磊磊的难题

题目描述

最近磊磊迷上了coding,立志要做一个苦逼的程序员 ^o^ ,他遇到了这样一个神题:要求从小到大输出两个小数之间的所有分母不超过10w的最简分数。磊磊郁闷了, 他甚至都不知道这样的分数有多少个于是他向你投来了哀怨的眼神……

输入要求

每组数据有5个数,abcdn(其中 a <= b, c <= d 且 a*d <= b*c),且5个数字都不超过10万。

输出要求

输出 大于a/b 小于 c/d 且分母不超过 的最简分数的个数输出占一行,处理到文件结尾。

假如输入

1 2 5 5 5 1 5 5 5 5

应当输出

4 8

提示

对于第一组数据 符合要求的最简分数有 2/33/43/54/5 答案为4

裸容斥,思路:

对于每一个分母确定分子的上下界,然后用容斥再求界内与分母互质的数,转换成小于上界与分母互质的数与小于下界与分母互质的数的个数差

TT,一开始上下界用的公式不是特别好。。wa40次TT

#include <cstdio>
#include <cmath>
using namespace std;
const double eps = 1e-6;
int n;
int aa[20], cnt;
long long dfs(int cur, int val)
{
    long long res=0;
    for (int i=cur; i<cnt; i++)
    {
        res += val/aa[i] - dfs(i+1, val/aa[i]);
    }
    return res;
}

void pnum(int tar)
{
    int ok = 0;
    while ((tar&1)==0)
    {
        ok = 1;
        tar = (tar>>1);
    }
    if (ok)
    {
        aa[cnt++] = 2;
    }
    int i=3;
    int limit = sqrt(tar)+1;
    while (i<=limit && tar>1)
    {
        ok = 0;
        while (tar%i==0)
        {
            ok = 1;
            tar /= i;
        }
        if (ok)
        {
            aa[cnt++] = i;
        }
        i += 2;
    }
    if (tar>1) aa[cnt++] = tar;
}
int main()
{
    int a, b, c, d;
    while (scanf ("%d%d%d%d%d", &a, &b, &c, &d, &n) == 5)
    {
        long long res = 0, x, y;
        for (int i=2; i<=n; i++)
        {
            x = 1.0*i*a/b+eps;
            y = 1.0*i*c/d-eps;
            if (x>=y) continue;
            cnt = 0;pnum(i);
            int tx = (y-dfs(0, y));
            int ty = (x-dfs(0, x));
            res += tx - ty;
        }
        printf ("%lld\n", res);
    }
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值