zoukankan      html  css  js  c++  java
  • 牛客练习赛89E-牛牛小数点【数论】

    正题

    题目链接:https://ac.nowcoder.com/acm/contest/11179/E


    题目大意

    定义(f(x))表示(frac{1}{x})的混循环节长度(如果没有循环节就是(0)),(T)组询问给出(l,r)

    [sum_{i=l}^rf(i) ]

    (1leq Tleq 100,1leq lleq rleq 10^{15})


    解题思路

    (a_i)表示(i)位之后的余数,那么出现循环节当且仅当(a_i)出现重复。

    [a_i=a_{i-1} imes 10\% nRightarrow a_i=10^i\%n ]

    那么出现循环节一定满足存在一个正整数(k)使得

    [a_i imes 10^kequiv a_i(mod n) ]

    [Rightarrow 10^kequiv 1(mod frac{n}{gcd(a_i,n)}) ]

    我们知道(10^kequiv 1(mod n))有解当且仅当(gcd(10,n)=1)

    也就是说我们要找到第一个(i)使得(gcd(10,frac{n}{gcd(a_i,n)})=1)

    (a_i)每次乘十,所以相当于(n)每次在质因数中去掉一个(2)(5),直到和(10)互质。

    但是这样还没有结束,因为如果没有循环节就是(0),而这里则会统计小数的长度,得减去这些情况,不难发现有循环节的话当且仅当存在某个(10^k\%n=0),也就是说(n)只由(2)(5)构成,暴力枚举这些数就好了。

    时间复杂度:(O(Tlog_2nlog_5 n))


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const ll P=998244353;
    ll T,l,r;
    int Ask(ll n){
        ll ans=n;
        for(ll i=1,pw=2;pw<=n;i++,pw=pw*2ll)ans=(ans+n/pw)%P;
        for(ll i=1,pw=5;pw<=n;i++,pw=pw*5ll)ans=(ans+n/pw)%P;
        for(ll i=1,pw=10;pw<=n;i++,pw=pw*10ll)ans=(ans-n/pw)%P;
        for(ll i=1,pw=1;pw<=n;i++,pw=pw*2ll)
            for(ll j=1,qw=1;pw*qw<=n;j++,qw=qw*5ll)
                (ans-=max(i,j))%=P;
        return (ans+P)%P;
    }
    signed main()
    {
        scanf("%lld",&T);
        while(T--){
            scanf("%lld%lld",&l,&r);
            printf("%lld
    ",(Ask(r)-Ask(l-1)+P)%P);
        }
        return 0;
    }
    
  • 相关阅读:
    Android APK安装过程介绍
    Android Linux自带iptables配置IP访问规则
    海康视频监控---Demo
    Go之获取Windows下文件是否隐藏
    Go之go与channel组合使用
    Go并发编程(四)
    Go错误处理(二)
    Go面向对象(三)
    判断两端日期是否重合
    Sql分页存储过程
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15333340.html
Copyright © 2011-2022 走看看