[BZOJ2820]YY的GCD
Posted Elder_Giang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ2820]YY的GCD相关的知识,希望对你有一定的参考价值。
2820: YY的GCD
Time Limit: 10 Sec Memory Limit: 512 MB Submit: 2248 Solved: 1207 [Submit][Status][Discuss]Description
Input
Output
Sample Input
10 10
100 100
Sample Output
2791
HINT
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; }
以上是关于[BZOJ2820]YY的GCD的主要内容,如果未能解决你的问题,请参考以下文章