题解 : 约数研究
Posted wqt-fft
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 : 约数研究相关的知识,希望对你有一定的参考价值。
这是本蒟蒻第一次写题解,好激动。
我下面介绍**四**种解法 _~~有两种比较神奇~~_
------------
# 方法一
先发一下正解吧,具体解释其他题解都有,我就不详细说了。重点是下面三种方法。
```cpp
#include <iostream>
using namespace std;
typedef long long ll;
ll n, ans;
int main()
cin >> n;
for (int i = 1; i <= n; i++)
ans += n / i;
cout << ans << endl;
return 0;
```
时间复杂度:O(n)~~应该是~~
极其~~简陋~~精简,不是吗?
------------
# 方法2
但本蒟蒻考试的时候抽风了没有想到。
这道题我看到题解里有许多巨佬已经把各种方法用上了,不过我要介绍一种方法,是当时我考模拟赛时想到的。那就是
# ~~_打表_~~
没错,你没有听错。我当时用暴力做只水了70分,我这时想到了我们机房的一位巨佬打表A了反素数,想着,干脆来一波打表吧~~感觉打表挺好玩的~~。
思路:暴力的时间复杂度是O(n*$\sqrtn$)~~打个根号打了5分钟才打出来,第一次写题解~~既然10^6的数据会炸。~~我们不如每10^5个数打一个表,然后暴力求解区间小于10^5的因数。~~
_~~当时考试时我给老师看了一下我的方法,然后老师把嘴里的茶都吐了出来,说:~~_
# 你这个毒瘤啊!
打表生成器:
```cpp
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxa 1000001
#define int long long
using namespace std;
int ans,n;
int zhi[maxa],vis[maxa];
void y(int x)
int k=sqrt(x);
for(int i=1;i<=k;i++)
if(x%i==0)ans+=2;
if(x==k*k)ans--;
void fp()
for(int i=1;i<=n;i++)
y(i);
main()
cin>>n;
fp();
cout<<ans;
```
AC代码:
```cpp
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxa 1000001
#define int long long
using namespace std;
int ans,n,m;
int zhi[maxa],vis[maxa];
int ans1[]=1166750,2472113,3829833,5221472,6638449,8075504,9529316,10997454,12478206,13970034;//传说中的打表
void y(int x)
int k=sqrt(x);
for(int i=1;i<=k;i++)
if(x%i==0)ans+=2;
if(x==k*k)ans--;
void fp()
for(int i=m;i<=n;i++)
y(i);
main()
cin>>n;
if(n>=100000)
ans+=ans1[(n/100000)-1];
m=n/100000;
m*=100000;
m++;
fp();
cout<<ans;
```
时间复杂度:O(n/10~~玄学的10~~*$\sqrtn/10$)
不过注意,如果你的测评~~姬~~机不好,可能有一个点会T。(999998)
------------
# 方法三
其实当时考试的时候我本来是用类似于素数筛的思想来做的,但是我WA了。我后来订正了一下。大概就是枚举每个数,如果有它的倍数,则ans+=2。平方数特判一下就可以了。
代码:
```cpp
#include <iostream>
#include <cstdio>
using namespace std;
int n,primes[1000005],pc=0,vis[1000005],cnt[1000005],ans;
int main()
cin>>n;
for(int i=1;i<=n;i++) cnt[i]=1;
//素数筛
for(int i=2;i<=n;i++) if(cnt[i]<=1)
primes[pc++]=i;
for(int j=1;j*i<=n;j++)
vis[i*j]++;
int tmp=j,c=2;
while(tmp%i==0) tmp/=i,c++;
cnt[i*j]*=c;
for(int i=1;i<=n;i++) ans+=cnt[i];
cout<<ans;
```
时间复杂度:O(nlogn).
------------
# 方法四
这种方法绝对是前无古人,后无来着的。因为这份代码是我们机房里的国家队卧底。他做到了传说中的
# n方过百万,暴力碾标算!
而且我们的老师重测了几遍,他的代码都跑的飞快,4~5ms,至多59ms。
他正好避过了所有的数据。
## 他,就是
# cpy大巨佬
代码:
(因为他太巨了,所以我怕这份代码吓坏洛谷。这里省略部分)
```
#include<bits/stdc++.h>
using namespace std;
int n;
long long ans[1000005],anss=1,j=1;
int main()
anss=1;
cin>>n;
for(int i=1;i<=n;i++) ans[i]=1;
for(int i=2;i<=n;i++)
//这里打上马赛克,因为他太巨了!
j=1;
for(int i=2;i<=n;i++)
anss+=ans[i];
cout<<anss;
```
时间复杂度: O(n^2)
经实测,该算法实际速度和方法1不相上下。
------------
以上就是本萌新的题解,这是我的第一个题解,写了两个多小时。还望各位神犇多多包容。
以上是关于题解 : 约数研究的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 1968 [Ahoi2005]COMMON 约数研究
BZOJ-1968-[Ahoi2005]COMMON 约数研究