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 }