「解题报告」[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;
}