[关闭]
@11101001 2018-05-10T10:30:26.000000Z 字数 1315 阅读 736

bzoj2005: [Noi2010]能量采集

莫比乌斯反演


题目链接

bzoj2005: [Noi2010]能量采集

题解

对于挡住i,j的点数显然是gcd(i,j)
那么就是求

枚举带约数




枚举约数d

复杂度

代码

  1. #include<cstdio>
  2. #include<algorithm>
  3. inline int read() {
  4. int x = 0,f = 1;
  5. char c = getchar();
  6. while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar(); }
  7. while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar();
  8. return x * f;
  9. }
  10. #define int long long
  11. const int maxn = 100007;
  12. int n,m,mu[maxn],prime[maxn],num;bool p[maxn];
  13. void get_mu() {
  14. mu[1] = 1; int k = maxn - 7;
  15. for(int i = 2;i <= k;++ i) {
  16. if(!p[i]) mu[i] = -1,prime[++ num] = i;
  17. for(int j = 1;j <= num && prime[j] * i <= k;++ j) {
  18. p[prime[j] * i] = 1;
  19. if(i % prime[j] == 0) break;
  20. mu[prime[j] * i] = mu[i] * -1;
  21. }
  22. mu[i] += mu[i - 1];
  23. }
  24. }
  25. inline int calc(int x) {
  26. int a = n / x ,b = m / x,ret = 0;
  27. for(int i = 1,last;i <= a;i = last + 1) {
  28. last = std::min(a / (a / i),b / (b / i));
  29. ret += (mu[last] - mu[i - 1]) * (a / i) * (b / i);
  30. }
  31. return ret;
  32. }
  33. main() {
  34. get_mu();
  35. n = read(),m = read();
  36. if(n > m) std::swap(n,m);
  37. int ans = 0;
  38. for(int i = 1;i <= n;++ i) ans += 2 * i * calc(i);
  39. printf("%lld\n",ans - n * m);
  40. return 0;
  41. }
  42. 
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注