lightoj 1007

lightoj 1007 - Mathematically Hard

链接http://www.lightoj.com/volume_showproblem.php?problem=1007

题意:给定一个区间[m, n],假设 小于m的与m互质的数的个数为 s(m),小于m+1的与m+1互质的数的个数为 s(m+1),……,小于n的与n互质的数的个数为 s(n)。如果 m == n,输出 a = s(m)*s(m),否则,输出 a = s(m)*s(m) + s(m+1)*s(m+1) + …… + s(n)*s(n)。数据规模为maxv = 5 * 10^6

思路:求出maxv内的所有数的 a(i) 值,则 i 的 a(i) = s(i)*s(i) + a(i-1), 所以[m, n] 内的值就为 a(n) - a(m-1) (递推一下就可以出来)。值得注意的是 a 数组要定义为 unsigned long long 型的。所以我们的重点就转移到如何求 s(i) 了。s(i) 是 i 内的与i 互质的数的个数,这个就涉及到欧拉函数的问题了,不明白的可以看下 hdoj 1286 这道题的解题报告 ( 链接:http://www.cnblogs.com/Duahanlang/archive/2013/05/02/3055454.html )。

代码如下:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 
 5 using namespace std;
 6 
 7 const int maxv = 5000005;
 8 unsigned long long a[maxv];
 9 
10 void count()        //求1~maxv的所有欧拉函数
11 {
12     memset(a, 0, sizeof(a));
13     for(int i = 2; i < maxv; ++i){
14         if(!a[i])    //第一个a[i] == 0 的都是素数
15         {
16             for(int j = i; j < maxv; j += i)    //素数的倍数
17             {
18                 if(!a[j])    a[j] = j;    //对素数倍数赋值
19                 a[j] = a[j]/i*(i-1);    //求欧拉函数的值
20             }
21         }
22     }
23     for(int i = 2; i < maxv; ++i)    //求平方和
24         a[i] = a[i-1] + a[i]*a[i];
25 }
26 
27 int main()
28 {
29     int n, m, t, i = 1;
30     count();
31     //freopen("lightoj1007.txt", "r", stdin);
32     scanf("%d", &t);
33     while(t--)
34     {
35         scanf("%d%d", &m, &n);
36         printf("Case %d: %llu
", i++, a[n]-a[m-1]);
37     }
38     return 0;
39 }
原文地址:https://www.cnblogs.com/Duahanlang/p/3192064.html