数论之欧拉函数约数和
题目链接:https://vjudge.net/contest/223051#problem/D
题目大意,有一个函数f(x),由x->f(x)的映射法则为,f(x)表示x的所有约数和。
题目要求的是φ(n)即从 i从1~n中的f(i) 有多少个为偶数。
这题的f(x)可以用唯一分解定理求出约数和,但是一看数据范围10e12,暴利的话必定会T,所以肯定要运用到数论的知识。
首先 根据唯一分解定理
得到这个公式
分析,观察样例发现,答案总是距离输入很近,不难想到用n-奇数的个数,就是ans。
那么f(i)什么时候为奇数呢?
首先
1.除了2以外的素数之外全是奇数,那无论多少个奇数相乘肯定还是奇数,因为
奇x奇=奇,所以当i的素因子中含有2时,特殊分析一下,无论几个2相乘相加肯定为偶数,然后再加上1,所以以2位素因子展开的项必为奇数,所以可以不用考虑2。
因为奇x奇=奇。奇x偶=偶。偶x偶=偶。发现了,一个数乘以奇数并不改变原本的奇偶性。
2.要使f(i)为奇数,还需要满足什么条件?只要展开项全为奇数就可以了。
因为每一项的底数为素数,都为奇数。观察一下
奇数+奇数=偶数,偶数+奇数=奇数。
所以有偶数项奇数相加时,得到的必为偶数,然后加上最开始的1,不就是奇数了吗?所以之要ai为偶数,那么f(i)肯定为奇数。
3.最后一步,先说结论,f(i)肯定为平方数,为什么呢?看下图。
因此,我们f(i)肯定是一个平方数,那怎么算个数呢?栗子:
11 ^ 2>=101>=10 ^ 2。那小于101的平方数有多少呢?1 2 3 4 5 6 7 8 9 10对吧。
也就是sqrt(i)的个数,完美解决。
然后发现样例中100 答案是 83 而不是这个算法的结果90,为什么呢?
根据之前推理的第一条,乘以2不影响f(i)的约数和的奇偶性,所以得到结论:
如果f(i)的和为奇数,那么2*f(i)肯定也为奇数。
所以 我们只要再减去sqrt(i/2)就好了。
得到解决公式
ans=n-sqrt(n)-sqrt(n/2);
数论很美妙。
代码附上
#include<bits/stdc++.h>
using namespace std;
#define ll long long int
int main()
{
ll n;
scanf("%d",&n);
for(int cas=1;cas<=n;cas++)
{
ll x;
scanf("%lld",&x);
ll ans;
ans=(ll)sqrt(x)+(ll)sqrt(x/2);
printf("Case %d: %lld\n",cas,x-ans);
}
}