标签:led style href == limit pac += data target
T = 10000
N, M <= 10000000
由对称性,不妨设$n\le m$
那么$ans=\sum_{\left(p\right)IsPrime}\sum_{i=1}^n\sum_{j=1}^m\left[gcd\left(i,j\right)=p\right]$
由其它一些经典的题目(比如[POI2007]ZAP)很轻易地可以得到
$ans=\sum_{\left(p\right)IsPrime}\sum_{d=1}^{\lfloor\frac{n}{p}\rfloor}\mu\left(d\right)\lfloor\frac{n}{pd}\rfloor\lfloor\frac{m}{pd}\rfloor$
由于在前$n$个数中质数的个数约为$\frac{n}{lnn}$个
那么即使是加上了分块优化时间复杂度也是$O\left(\frac{n\sqrt{n}}{lnn}\right)$肯定会TLE
考虑设$pd=T$
那么$ans=\sum_{T=1}^{n}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{p\mid T}\mu\left(\frac{T}{p}\right)$
那么加上分块优化和前缀和处理后单次询问的时间复杂度就是$O\left(\sqrt{n}\right)$
总时间复杂度$O\left(T\sqrt{n}\right)$
#include <cstdio> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 10000000 + 10; bool mark[maxn] = {0}; int pri[664580], prn = 0; int mu[maxn], sum[maxn]; void shai(){ mu[1] = 1; for(int i = 2; i < maxn; i++){ if(!mark[i]){ mu[i] = -1; pri[++prn] = i; } for(int j = 1; j <= prn && i * pri[j] < maxn; j++){ mark[i * pri[j]] = true; if(i % pri[j] == 0){ mu[i * pri[j]] = 0; break; } else mu[i * pri[j]] = -mu[i]; // = mu[pri[j]] * mu[i] } } for(int i = 1; i <= prn; i++) for(int j = 1; j * pri[i] < maxn; j++) sum[pri[i] * j] += mu[j]; sum[0] = 0; for(int i = 1; i < maxn; i++) sum[i] += sum[i - 1]; } int main(){ shai(); int T, n, m; ll ans; scanf("%d", &T); while(T--){ scanf("%d %d", &n, &m); if(n > m) swap(n, m); ans = 0; for(int p, i = 1; i <= n; i = p + 1){ p = min(n / (n / i), m / (m / i)); ans += (ll) (sum[p] - sum[i - 1]) * (n / p) * (m / p); } printf("%lld\n", ans); } return 0; }
标签:led style href == limit pac += data target
原文地址:http://www.cnblogs.com/ruoruoruo/p/7678296.html