Sigma Function
LightOJ - 1336Sigma function is an interesting function in Number Theory. It is denoted by the Greek letter Sigma (σ). This function actually denotes the sum of all divisors of a number. For example σ(24) = 1+2+3+4+6+8+12+24=60. Sigma of small numbers is easy to find but for large numbers it is very difficult to find in a straight forward way. But mathematicians have discovered a formula to find sigma. If the prime power decomposition of an integer is
Then we can write,
For some n the value of σ(n) is odd and for others it is even. Given a value n, you will have to find how many integers from 1 to n have even value of σ.
Input
Input starts with an integer T (≤ 100), denoting the number of test cases.
Each case starts with a line containing an integer n (1 ≤ n ≤ 1012).
OutputFor each case, print the case number and the result.
Sample Input4
3
10
100
1000
Sample OutputCase 1: 1
Case 2: 5
Case 3: 83
Case 4: 947
这道题十分有意思
题意:它告诉我们一个公式是用来求每个数的因子和的公式,当然了,这个和可能是奇数也可能是偶数,所以题目给我们一个n,让我们求1~n,n个数中因子和是偶数的个数。
思路:这道题给你这个公式就是用来迷糊人的,n的数据量达到1e12,并且有100组样例,所以暴力用公式求和挨个判断是不可能的,因此需要对这个式子进行仔细的观察。
观察1:我们知道一个公理那就是 偶数 * 偶数 = 偶数; 奇数 * 偶数 = 偶数; 奇数 * 奇数 = 奇数;因此我们的第一个发现就是整道题确定因子和是不是奇数是好确定的,因为它只有一种情况就是奇数*奇数才是奇数,因此我们确定了我们的方向,先求因子和是奇数的个数,然后用总数n减去。
观察2:所有素数中只有2是个偶素数,其他所有素数全是奇素数
观察3:我们观察公式
整数唯一分解定理:x = p1^a1 * p2^a2 *……* pk^ak
因数和公式 σ(x) = (1+p1+p1^2+……+p1^a1) * (1+p2+p2^2+……+p2^a2) *……* (1+pk+pk^2+……+pk^ak)
我们的目的就是使得(1+pi+pi^2+……+pi^ai)这个东西都是奇数
现在考虑两种情况
⑴pi是2,也就是x中存在2这个偶素数为因数我们发现pi+pi^2+……+pi^ai这一部分一定是偶数,没有问题吧,然后+1一定是奇数,所以当pi=2的情况这部分等比数列求和一定是奇数。
⑵pi是其他素数也就是说pi都是奇数,那么我们继续观察这个式子(1+pi+pi^2+……+pi^ai),我们这个式子发现每一项都是奇数
那么如果ai是偶数,pi+pi^2+……+pi^ai就会有偶数个奇数相加最后结果就是偶数,然后+1,(1+pi+pi^2+……+pi^ai)整体就是奇数了,所以我们需要让ai是偶数此时我们回到整数唯一分解定理看x = p1^a1 * p2^a2 *……* pk^ak,如果ai都是偶数,是不是这个式子可以变成x = p1^(a1'*2) * p2^(a2'*2) *……* pk^(ak'*2) = (p1^a1' * p2^a2' *……* pk^ak')^2,所以到这一步大家一定发现了如果这个数是个完全平方数。
大家一定注意了,这是没有2素因子的情况,如果没有2这个素因子一定是完全平方数,如果有2,首先其他部分一定是完全平方数,再乘上2的几次方就是一个完全平方数*2的几次方,所以它要么也是一个完全平方数(2的偶数次方)或者2*一个完全平方数(2的奇数次方,提出一个2其他构成完全平方数)
总结一下上面我们的思路就是找到n以内的完全平方数的个数,和n以内的完全平方数的二倍即x^2 <= n和2 * (x^2) <= n的个数。那么我们如何实现呢
方法一:
遍历i=0到i*i <= n这样每个i*i就代表n内的一个完全平方数计数+1,同时再判断如果2*i*i<=n那么这是2倍完全平方数计数+1
最后总数减去即可
code1:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
int main(){
int T,cas = 0;
ll n;
scanf("%d",&T);
while(T--){
scanf("%lld",&n);
ll ans = 0;
for(ll i = 1LL; i * i <= n; i++){
ans++;
if(2 * i * i <= n)
ans++;
}
printf("Case %d: %lld\n",++cas,n-ans);
}
return 0;
}
方法二:
是一种更加简洁的方式,
我们要找 x^2 <= n和2 * (x^2) <= n,所以cnt1 <= √n cnt2 <= √(n/2), cnt1+cnt2就是总的计数个数
如果大家不太理解可以这样想,我们对数求根号比如√n = cnt1,那么这个cnt1*cnt1就是不大于n的最大整数,所以
从1-cnt1中的每个数他们的平方都在n范围内,恰好就是cnt1个数啦。
code2:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
int main(){
int t,cas = 0;
scanf("%d",&t);
while(t--){
ll n;
scanf("%lld",&n);
ll ans = n;
ans -= (int)sqrt(n);
ans -= (int)sqrt(n/2);
printf("Case %d: %lld\n",++cas,ans);
}
return 0;
}
我喜欢数论的原因就是简洁的代码和公式中包含如此之多的奥妙和道理