BZOJ 2818: Gcd
二次联通门 : BZOJ 2818: Gcd
/* BZOJ 2818: Gcd 莫比乌斯反演 推了个很暴力的式子,居然跑过去了 做法大致就是调换枚举顺序 枚举素数,把gcd(i,j)=p的数对加起来 */ #include <cstdio> #include <iostream> #define rg register typedef long long LL; inline void read (int &n) { rg char c = getchar (); for (n = 0; !isdigit (c); c = getchar ()); for (; isdigit (c); n = n * 10 + c - '0', c = getchar ()); } #define Max 10000069 int p[Max], mu[Max]; bool is[Max]; void Euler (int N) { rg int i, j, k; int C = 0; mu[1] = 1; for (i = 2; i <= N; ++ i) { if (!is[i]) p[++ C] = i, mu[i] = -1; for (j = 1; j <= C; ++ j) { if ((k = i * p[j]) > N) break; is[k] = true; if (i % p[j] == 0) { mu[k] = 0; break; } else mu[k] = -mu[i]; } } for (i = 1; i <= N; ++ i) mu[i] += mu[i - 1]; } inline int min (int a, int b) { return a < b ? a : b; } int main (int argc, char *argv[]) { int N; read (N); rg int i, j, pos; Euler (Max - 1); long long res = 0; int L; for (pos = 1; p[pos] <= N && p[pos]; ++ pos) for (i = 1, L = N / p[pos]; i <= L; i = j + 1) j = L / (L / i), res += (LL) (L / i) * (L / i) * (mu[j] - mu[i - 1]); std :: cout << res; return 0; }
myj 吊打我Orz,xxy 捆起来打我Orz,myl 文化课上天Orz, lrh 姿势水平敲高Orz, hkd 特别胖Orz%%%,cys 智商感人Orz,syl zz专业Orz,我没有学上, 我们未来一片光明