「解题报告」[luoguP6583]回首过去 (数论分块)

「解题报告」[luoguP6583]回首过去 (数论分块)

传送门

题面

题意

给定正整数 \(n\), 求出有序整数对 \((x,y)\) 的个数, 满足 \(1\le x,y \le n\)\(\frac{x}{y}\) 可以表示为十进制有限小数.

数据范围

\(1 \le n \le 10^{12}\)


思路

\(\frac{x}{y}\) 是十进制有限小数, 则 \(\frac{y}{\gcd(x,y)}\) 的质因子只有 \(2\)\(5\).

枚举 \(i,j,d\) , 表示 \(y=2^i5^j\cdot d\) , 则 \(x\) 的数量为 \(\left\lfloor \frac{n}{d} \right\rfloor\) , 可以数论分块.

枚举 \(d\) 的时候, 需要满足 \(d\) 不能整除 \(2\)\(5\) , 所以数论分块的时候要容斥一下.

因为每 \(10\) 个数中必定有 \(6\) 个数是 \(2\)\(5\) 的倍数, 所以数论分块的时候先处理整十的部分, 对于剩下的暴力枚举一下即可.


代码

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
ll n,ans,q[400],cnt,tms;
bool cmp(ll x,ll y){ return x>y; }
int main(){
    cin>>n;
    ll t2=1;
    while(t2<=n){
	ll t5=1;
	while(t2*t5<=n){
	    q[++cnt]=t2*t5;
	    t5*=5ll;
	}
	t2*=2ll;
    }
    ll sum=0; q[0]=n+1;
    sort(q+1,q+1+cnt,cmp);
    for(int p=1;p<=cnt;p++){
	for(ll i=n/q[p-1]+1,j;i<=n/q[p];i=j+1){
	    j=min(n/q[p],n/(n/i));
	    ll k=(j-i+1)/10,num=4*k;
	    for(k=i+k*10;k<=j;k++)
		if(k%2&&k%5) num++;
	    sum+=num*(n/i);
	}
	ans+=sum;
    }
    printf("%lld\n",ans);
    return 0;
}	
posted @ 2020-06-16 22:10  BruceW  阅读(163)  评论(0编辑  收藏  举报