Sigma Function

题目

给定一个n<=1e12,求在n之前的正整数,有多少个约数之和为偶数。

分析

我在题目的公式上看了半天推不出结论来。此题十分适合打表观察规律,所以可以打表看看。
打表结果:

1 : odd
2 : odd
3 : even
4 : odd
5 : even
6 : even
7 : even
8 : odd
9 : odd
10 : even
11 : even
12 : even
13 : even
14 : even
15 : even
16 : odd
17 : even
18 : odd
19 : even
20 : even
21 : even
22 : even
23 : even
24 : even
25 : odd
26 : even
27 : even
28 : even
29 : even
30 : even
31 : even
32 : odd
33 : even
34 : even
35 : even
36 : odd
37 : even
38 : even
39 : even
40 : even
41 : even
42 : even
43 : even
44 : even
45 : even
46 : even
47 : even
48 : even
49 : odd
50 : odd
51 : even
52 : even
53 : even
54 : even
55 : even
56 : even

可以得出规律:约数之和的数,要么是平方数,要么除以2之后是个平方数.所以我们可以把满足这条件的统计出来,就是约数之和为奇数的个数。然后n-约数之和为奇数的个数就可以了。

AC代码

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 1e6+10;
typedef long long ll;
int T;
ll fun(ll x){
    ll res = 0;
    for(int i = 1;i<=x;i++){
        if(x%i == 0) res += i;
    }
    return res%2;
}
int main(){
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
//    for(int i = 1;i<=1000;i++){ //打表
//        cout<<i<<" : ";
//        if(fun(i)) cout<<"odd"<<endl;
//        else cout<<"even"<<endl;
//    }
    cin>>T;
    int kase = 0;
    while(T--){
        ll n,odd = 0;
        scanf("%lld",&n);
        for(ll i = 1;i*i<=n;i++){
            odd++;
            if(2*i*i<=n){
                odd++;
            }
        }
        printf("Case %d: %lld\n",++kase,n-odd);
    }
    return 0;
}