几亿年没更的博客终于想起来了。。。。
其实不是我不想更,而是太水了发上去不好意思。。。。
但是觉得不能辜负zzk巨佬的贴心教导,所以还是写一写吧,毕竟好久没认真学一个新算法了
题目链接
首先80分的部分不难想
对于每一个分母,除去2和5对答案都没有影响,当把所有2、5都除去之后统计即可,复杂度(O(n))
Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
void file(string s){freopen((s+".in").c_str(),"r",stdin),freopen((s+".out").c_str(),"w",stdout);}
int read()
{
int a=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-f;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
a=a*10+ch-'0';
ch=getchar();
}
return a*f;
}
int n;
long long ans;
signed main()
{
// file("");
n=read();
for(int i=1;i<=n;++i){
int x=i;
while(!(x%2))x/=2;
while(!(x%5))x/=5;
ans+=n/x;
}
cout<<ans;
return 0;
}
100分部分就用了一些技巧
首先把这一部分
while(!(x%2))x/=2;
while(!(x%5))x/=5;
ans+=n/x;
改成
if(i%2==0||i%5==0)continue;
for(int j=1;j*i<=n;j*=2){
for(int k=1;k*i*j<=n;k*=5){
tmp++;
}
}
ans+=n/l*tmp;
也就是把找每个数对应的数是多少变成了算每个数能对应多少个数
接下来我们就发现只要能优化tmp的求解我们就能进行优化了
这里用到了整除分块的思想,先把所有因子只有2和5的数从小到大求出来
void build()
{
for(int i=1;i<=n;i*=2){
for(int j=1;j*i<=5;j*=5){
num[++tot]=i*j;
}
}
sort(num+1,num+1+tot);
}
那么对于每一个tmp对应的是哪一个区间就可以求出来
最后用容斥求一下每个区间有多少个需要统计的数(就是没有被continue的数)就可以了
复杂度(O(sqrt n))
Code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
void file(string s){freopen((s+".in").c_str(),"r",stdin),freopen((s+".out").c_str(),"w",stdout);}
int read()
{
int a=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-f;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
a=a*10+ch-'0';
ch=getchar();
}
return a*f;
}
int n,ans,tot;
int num[5000];
void build()
{
for(int i=1;i<=n;i*=2){
for(int j=1;j*i<=n;j*=5){
num[++tot]=i*j;
}
}
sort(num+1,num+1+tot);
}
int makenum(int l,int r)
{
l--;
int num2,num5,num10;
num2=r/2-l/2;
num5=r/5-l/5;
num10=r/10-l/10;
return r-l-num2-num5+num10;
}
int makef(int x)
{
return upper_bound(num+1,num+tot+1,x)-num-1;
}
signed main()
{
// file("");
n=read();
build();
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l);
ans+=makef(n/l)*makenum(l,r)*(n/l);
}
cout<<ans;
return 0;
}