• 洛谷P6583 回首过去


    题目链接

    https://www.luogu.com.cn/problem/list?keyword=6583&page=1

    题目大意

    给定一个n,求有多少对 (x , y) 满足 1 <= x <= n , 1 <= y <= n 且 x / y 是有限小数

    解题思路

    首先有限小数的定义为当分数为最简形式时分母只包含 2 、5 两个质因子

    于是我们可以就用 $dfrac {bc}{ac}$ 来表示任何一个有限小数

    ( 其中 a 为 2、5 两个质因子构成的数 , c 为不包含 2、5 两个质因子的数 , b 随意 )

    我们可以考虑枚举 c , 那么 $ans=sum ^{n}_{c=1}dfrac {n}{c} imes fleft( dfrac {n}{c} ight) $

    其中 (n / c) 为 b 的取值范围 , f(n / c) 为 [1 , n / c] 内 a 的个数

    对于 f(n / c) 它会随着 c 的增大单调递减 , 那么我们总共只需要 O(n) 的复杂度就可求出

    而 $sum ^{n}_{c=1}dfrac {n}{c}$ 又很显然是个经典的整除分块式 , 所以再套个整除分块的模板就差不多

    不过值得注意的是这里的 c 是不包含 2、5 两个质因子的数 , 所以对于每个块我们要减去包含 2、5 两个质因子的数

    实现起来很简单 , 根据容斥原理减去块内 2 的倍数的数 , 再减去块内 5 的倍数的数 , 然后再加上块内 10 的倍数的数即可

    AC_Code

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N = 3e5 + 10;
    int a[N] , m , now = 1; 
    int f(int x)
    {
        while(a[now] > x && now ) now -- ;
        return now ;
    }
    signed main()
    {
        ios::sync_with_stdio(false);
        int n ;
        cin >> n;
        for(int i = 1 ; i <= n ; i *= 2)
            for(int j = 1 ; j * i <= n ; j *= 5)
                a[++ m] = i * j;
        now = m;
        sort(a + 1 , a + 1 + m);
        int ans = 0;
        for(int l = 1 , r ; l <= n ; l = r + 1)
        {
            r = n / (n / l);
            int cnt1 = r - l + 1 , cnt10 = r / 10 - (l - 1) / 10;
            int cnt2 = r / 2 - (l - 1) / 2 , cnt5 = r / 5 - (l - 1) / 5;
            int sum = cnt1 - cnt2 - cnt5 + cnt10;
            ans += sum * (n / l) * f(n / l);
        }
        cout << ans << '
    ';
        return 0;
    }
    凡所不能将我击倒的,都将使我更加强大
  • 相关阅读:
    设计模式开始--工厂模式
    设计模式开始--UML类之间关系表示
    设计模式开始1--不明觉厉
    Gas Station
    Validate Binary Search Tree
    Word Ladder
    (转)基于快速排序的TOPK算法
    Number of 1 Bits
    Word Search
    Rotate Array
  • 原文地址:https://www.cnblogs.com/StarRoadTang/p/13032323.html
Copyright © 2020-2023  润新知