【SPOJ5971】LCMSUM
【问题描述】
求sigma(lcm(i,n)),1 <= i <= n。
【分析】
跟求sigma(gcd(i,n)) 有点像(POJ2480 Longge's problem),都是枚举n的约数。
首先有个性质,在1到n中与n互质的数都是成对出现的,且他们的和为n * phi(n) / 2。
例如30,在1到n中与30互质的数有1,7,11,13,17,19,23,29.其中1 + 29= 30,7 + 23 = 30,11 + 19 = 30,13+17 =30。(1是例外,虽然2也是例外,phi(2) = 1,但是结果是一样的)
所以,当gcd(i,n) = k,sigma(i) = n / k * phi(n / k) / 2 * k。
lcm(i,n) = i * n / k, sigma(lcm(i,n)) = sigma(n * n/ k * phi(n/k) / 2 * k/ k) = n * sigma(n/ k * phi(n/k) / 2)
接着只要枚举n的约数累加就行了,虽然慢但是还是能A的。
这道题时限卡得比较紧,所以不仅筛法,求phi都要O(N),求约数要注意时间,而且也要注意细节。记得用long long,不然会挂掉,也不能乱用long long,不然可能会TLE。
【代码】
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; int n,pt =0,t; long long ans; bool p[1000005]; long long prime[500000],phi[1000005],fact[4000],num[4000]; void Init() { phi[1] = 1; for (int i = 2;i <= 1000000;i ++) { if (!p[i]) pt ++, prime[pt] = i,phi[i] = i - 1; for (int j = 1;j <= pt && (long long)i * prime[j] <= 1000000;j ++) { p[prime[j] * i] = true; if (i % prime[j] == 0) { phi[i * prime[j]] = prime[j] * phi[i]; break; } else phi[i * prime[j]] = (prime[j] - 1) * phi[i]; } } } void dfs(int i,long long now) { if (i == t + 1) { //cout << now << ' '<< phi[now] << endl; ans += now * phi[now] / 2; return; } dfs(i + 1,now); for (int j = 1;j <= num[i];j ++) { now *= fact[i]; dfs(i + 1,now); } } void div(long long n) { t = 0; for (int i = 1;i <= pt;i ++) { if (prime[i] * prime[i] > n || !p[n]) break; if (n % prime[i]) continue; fact[++t] = prime[i]; num[t] = 0; while (n % prime[i] == 0) n /= prime[i],num[t] ++; } if (n > 1 && !p[n]) fact[++t] = n,num[t] = 1; } int main() { int Tcase; scanf("%d",&Tcase); Init(); while (Tcase--) { scanf("%d",&n); ans = 0; div(n); dfs(1,1); printf("%lld\n",(long long)(ans + 1) * n); // +1是为了处理第一个性质的1 } }