洛谷P6583 回首过去

涉及知识点:容斥原理、数论分块

前言

本题对于数论分块类型题目推式子和处理方法有很大的启发

题面

Link

给定正整数 \(n\),求有序实数对 \((x,y)\) 满足 \(1\leq x,y \leq n\) 并且使得 \(\frac{x}{y}\) 为有限小数(本题题意下整数可视作小数点后有 \(0\) 位的有限小数)。

分析

首先我们要明确一点性质,那就是 \(\frac{x}{y}\) 是有限小数当且仅当该分数化为最简分数后,分母分解质因数的结果没有除了 \(2\)\(5\) 以外的其他数

既然分数 \(\frac{x}{y}\) 是否为有限小数只和化简后的分母有关,那么我们可以尝试从 \(1\)\(n\) 枚举分母 \(y\),情况有两种如下:

  • \(y\) 分解质因数之后不存在 \(2\)\(5\) 除外的数

    这种情况下,\(x\) 可以为任何值,都可以保证该分数为有限小数,因此满足该分数为有限小数的分子 \(x\) 取值有 \(n\) 种。

  • \(y\) 分解质因数存在 \(2\)\(5\) 除外的数

    我们令 \(y=ab\),其中 \(a\) 分解质因数只包含 \(2\)\(5\)\(b\) 分解质因数只包含除了 \(2\)\(5\) 的其他数,易得 \(b\ne 1\)。此时如果要使得该分数为有限小数,说明该分数化为最简后分母只剩下 \(a\),说明化简前的分子一定能被 \(b\) 整除才能使得分子分母能同时消去 \(b\)。可以发现满足 \(b\mid x \and 1\leq x\leq n\)\(x\) 共有 \(\lfloor \frac{n}{b} \rfloor\) 种。

以上两种情况总结一下,得到 \(\Large ans=\sum\limits_{i=1}^n\lfloor\frac{n}{\frac{i}{2^p5^q}}\rfloor\),其中 \(p\)\(q\) 是极大的,情况一时 \(p\)\(q\) 均为 \(0\)


有了以上这几点分析,你就可以获得 80 分的好成绩了,那么接下来该如何继续优化呢?

首先我们可以发现答案是一堆分数向下取整的和,从这一点就可以观察出这是一个类似数论分块的地方,但是与数论分块常见的形式 \(\Large\sum\limits_{i=1}^{n}\lfloor\frac{n}{i}\rfloor\) 不同的是,本题分数的分子不是 \(i\) 而是 \(\Large\frac{n}{\frac{i}{2^p5^q}}\)。我们令 \(\large t=\frac{i}{2^p5^q}\),另外由于 \(i\leq n\),所以易得 \(\large t\leq \frac{n}{2^p5^q}\),另外 \(t\) 不含质因子 \(2\)\(5\),由此原式化为 \(\Large ans=\sum\limits_{p=0}^{log_2 n}\sum\limits_{q=0}^{log_5 n}\sum\limits_{t=1}^{\frac{n}{2^p5^q}}\large\lfloor\frac{n}{t}\rfloor\times[2\nmid t]\times[5\nmid t]\),我们只需要 \(O(\sqrt n)\) 的时间复杂度内对 \(\Large\sum\limits_{t=1}^{\frac{n}{2^p5^q}}\lfloor\frac{n}{t}\rfloor\) 进行数论分块(由于 \(t\) 不含质因子 \(2\)\(5\),数论分块时需要容斥,具体见代码),统计每块的前缀和,再 \(O(\log^2 n)\) 枚举 \(p\)\(q\),每次查找时 \(O(\log n)\) 二分找到最后一个完整的块,再用数论分块同样的方法 \(O(1)\) 求出剩下多出来的一段的贡献,总复杂度为 \(O(\sqrt n + \log^3 n)\)

代码

#include<bits/stdc++.h>
using namespace std;
template<class T>inline void rd(T &x){
    T res=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1; ch=getchar();}
    while(isdigit(ch)){res=res*10+ch-'0';ch=getchar();}
    x=res*f;
}
template<class T>inline void wt(T x,char endch='\0'){
    static char wtbuff[20];
    static int wtptr;
    if(x==0){
        putchar('0');
    }
    else{
        if(x<0){x=-x;putchar('-');}
        wtptr=0;
        while(x){wtbuff[wtptr++]=x%10+'0';x/=10;}
        while(wtptr--) putchar(wtbuff[wtptr]);
    }
    if(endch!='\0') putchar(endch);
}
typedef long long LL;
const LL MAXN=1e12+5,MAXT=2000005;
LL n,ans=0,posr[MAXT],sum[MAXT],cnt=0;
inline LL len(LL l,LL r){//容斥去除掉能被2或5整除的t
    return (r-l+1) - (r/2-(l-1)/2) - (r/5-(l-1)/5) + (r/10-(l-1)/10);
}
int main(){
    rd(n);
    ans=0,cnt=0;
    for(LL l=1,r;l<=n;l=r+1){
        r=n/(n/l);
        posr[++cnt]=r;
        sum[cnt]=sum[cnt-1]+len(l,r)*(n/l);
    }
    LL cnt2=log(n)/log(2),sum2=1;
    for(LL i=0;i<=cnt2;i++,sum2*=2){
        LL cnt5=log(n/sum2)/log(5),sum5=1;//计算log_5(cnt5)用了换底公式
        for(LL j=0;j<=cnt5;j++,sum5*=5){
            LL cur=n/sum2/sum5;
            LL id=lower_bound(posr+1,posr+1+cnt,cur)-posr-1;
            ans+=sum[id]+len(posr[id]+1,cur)*(n/cur);
        }
    }
    wt(ans,'\n');
    return 0;
}
posted @ 2023-09-26 22:48  MessageBoxA  阅读(21)  评论(0编辑  收藏  举报