大意很好理解,就是求和
其中 lcm(i, j) 表示整数 i 和 j 的最小公倍数,结果模上 2^32
大致思路:
这个题和SPOJ 5971很像 可以先看看 SPOJ 5971题解
这答题我们先把需要求的项列出来得到下面这个样子:
lcm(1, 2) lcm(1, 3) lcm(1, 4) .... lcm(1, n)
lcm(2, 3) lcm(2, 4)..... lcm(2, n)
lcm(3, 4)..... lcm(3, n)
...... lcm(n - 1, n)
很明显求和式可以转变为:
这样子就很好求了, 每次求出 sigma(lcm( j , k), 1 <= j <= k)之后将结果求和就是要的结果,而且这答题中相比SPOJ 5971来说要简单一点 (少一项特殊的勉强算简单吧)
最终共识SPOJ 5971的题解里写过了~
代码如下:
Result : Accepted Memory : 60280 KB Time : 848 ms
/* * Author: Gatevin * Created Time: 2014/8/4 13:32:22 * File Name: test.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; typedef unsigned long long ulint; #define maxn 3000010 int phi[maxn]; ulint ans[maxn]; ulint f[maxn]; int t; int n; void initial() { memset(phi, 0, sizeof(phi)); phi[1] = 1; for(int i = 2; i < maxn; i++) { if(!phi[i]) { for(int j = i; j < maxn; j += i) { if(!phi[j]) { phi[j] = j; } phi[j] = phi[j] / i * (i - 1); } } } memset(ans, 0, sizeof(ans)); memset(f, 0, sizeof(f)); for(int i = 2; i < maxn; i++) { // f[i] += i*((ulint)phi[i]) / 2 * i; // ans[i] = ans[i - 1] + f[i]; for(int j = i; j < maxn; j += i) { f[j] += ((ulint)phi[i])*i / 2 * j; } ans[i] = ans[i - 1] + f[i]; } return; } int main() { scanf("%d",&t); initial(); for(int cas = 1; cas <= t; cas++) { scanf("%d", &n); printf("Case %d: %llu\n", cas, ans[n]); } return 0; }