神炎皇 解题报告
神炎皇
问题描述
神炎皇乌利亚很喜欢数对, 他想找到神奇的数对。
对于一个整数对\((a,b)\), 若满足 \(a+b\le n\) 且 \(a+b\) 是 \(ab\) 的因子, 则称为神奇的数对。 请问这样的数对共有多少呢?
输入格式
一行一个整数 \(n\)。
输出格式
一行一个整数表示答案, 保证不超过 \(64\) 位整数范围。
数据范围与约定
对于\(20\%\)的数据 \(n\le 1000\);
对于\(40\%\)的数据 \(n\le 100000\);
对于\(60\%\)的数据 \(n\le 10000000\);
对于\(80\%\)的数据 \(n\le 1000000000000\);
对于\(100\%\)的数据 \(n\le 100000000000000\)。
说一下考试时候的打表历程吧(拿了\(40pts\),如果让我交答案表了就有\(60pts\)了)
第一个表的枚举\(a+b\),然后暴力找\(a,b\)
得到了一个没什么用的答案表
把数对打出来
研究一下发现每个\(a+b\)的贡献可以这么算,设\(f(x)\)为\(x=a+b\)的贡献
则\(f(x)=\sum_{i=1}^x[x|i^2]\)
证明一下也不难,因为\(gcd(i,x)=gcd(x-i.x)\)
发现这样没什么卵用,继续打表发现
后面的都是第一个的倍数,理解起来也非常简单,考虑每个数最小满足的数怎么搞。
发现就是唯一分解以后,指数除\(2\)向上取整,拿原数除最小数即为个数\(-1\)(因为自己不算),则又有
\(x=\prod p_i^{c_i}\),\(f(x)=\prod p_i^{\lfloor\frac{c_i}{2}\rfloor}-1\)
令\(g(x)=\prod p_i^{\lfloor\frac{c_i}{2}\rfloor}\)
发现\(g(x)\)是积性函数,然而窝并没想到\(O(n)\)的筛法,只好只拿了\(40pts\)
正解:
设有一对满足条件的数对\((a,b)\)
设\(d=gcd(a,b),a'=\frac{a}{d},b'=\frac{b}{d}\)
则要满足条件\((a'+b')d|a'b'd^2\)
即\((a'+b')|a'b'd\)
因为\((a',b')=1\),所以\((a'+b',a')=(a'+b',b')=1\),所以\((a'+b',a'b')=1\)
则条件为\((a'+b')|d\)
设\(i=a'+b'\),\(d=ki\),那么有\(id=i^2k\le n\)
发现枚举\(i\)只需要到\(\sqrt n\)就可以了,于是枚举\(i\)
对于一个\(i\),\(k\)的取值个数为\(\lfloor\frac{n}{i^2}\rfloor\)
考虑\(i\)内部的情况,发现是\(\varphi(i)\),原因很简单,也是因为\(gcd(i,x)=gcd(i,i-x)\),考虑一下成对出现就可以了。
那么答案就为\(\sum_{i=1}^{\sqrt n}\varphi(i)\lfloor\frac{n}{i^2}\rfloor\)
总结:
- 数据范围根号提示
- 想办法使用\(\varphi ,\mu\)什么的
- 胡乱更换枚举项试试(这是很多题的核心了,谁枚举的少好算,我就找谁)
- 不要忘记打个表
Code:
#include <cstdio>
#define ll long long
const int N=1e7;
int pri[N+10],phi[N+10],ispri[N+10],cnt;
ll ans,n;
void init()
{
for(int i=2;i<=N;i++)
{
if(!ispri[i])
{
pri[++cnt]=i;
phi[i]=i-1;
}
for(int j=1;j<=cnt&&pri[j]*i<=N;j++)
{
ispri[i*pri[j]]=1;
if(i%pri[j]==0)
{
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
else
phi[i*pri[j]]=phi[i]*(pri[j]-1);
}
}
}
int main()
{
init();
scanf("%lld",&n);
for(ll i=1;i*i<=n;i++)
ans=ans+phi[i]*(n/(i*i));
printf("%lld\n",ans);
return 0;
}
2018.11.1