luogu P3455 [POI2007]ZAP-Queries
阿新 • • 發佈:2018-12-15
luogu P3455 [POI2007]ZAP-Queries
題目讓我們求出
以下的n 是 題目中的 a, m 是 b
\[\sum_{i=1}^{n}\sum_{i = 1}^m [gcd(i,j) == d]\]
因為有\[gcd(i , j) == d\]
\[gcd(i / d , j / d) == 1\]
設\(f(k)=\sum_{i=1}^n\sum_{i=1}^m[gcd(i,j)==k]\)套用
\[\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)==d] = \sum_{i=1}^{\frac nd}\sum_{j=1}^{\frac md}gcd(i,j)==1\]
套用反演公式2
\[g(x) = \sum_{x|y}f(y)=\sum_{x|y}\sum_{i=1}^n\sum_{i=1}^mgcd(i,j)==y=\]
\[\sum_{i=1}^n\sum_{i=1}^m\sum_{x|gcd(i,j)}=\sum_{i=1}^n\sum_{i=1}^m\sum_{x|i,x|j}=[\frac nx][\frac mx]\]
我們求
\[f(1) = \sum_{1|y}\mu(\frac y1)g(y)=\sum_{y}^{min(n,m)}\mu(y)[\frac {\frac nd}{y}][\frac {\frac md}{y}]\]
可以用字首和加分塊使一次操作達到\(O(\sqrt n)\)
所以總複雜度:\(O(T \sqrt n)\)
#include <iostream> #include <cstdio> #define ll long long const int maxN = 50000 + 7; const int N = 50000; int mu[maxN] , prime[maxN], num; bool vis[maxN]; void init() { mu[1] = 1; for(int i = 2;i <= N;++ i) { if( !vis[i] ) { prime[++ num] = i; mu[i] = -1; } for(int j = 1;j <= num && prime[j] * i <= N;++ j) { vis[prime[j] * i] = true; if(i % prime[j] == 0) break; mu[i * prime[j]] = -mu[i]; } } for(int i = 1;i <= N;++ i) mu[i] += mu[i - 1]; return ; } inline void swap(int &a,int &b) {a ^= b ^= a ^= b;return;} inline int min(int a,int b) {return a > b ? b : a ;} int main() { int T; scanf("%d",&T); init(); while(T --) { int a,b,k; scanf("%d%d%d",&a,&b,&k); a /= k;b /= k; if(a > b) swap(a,b); long long ans = 0; for(int l = 1,r;l <= a;l = r + 1) { r = min(a / (a / l),b / (b / l)); ans += 1LL * ( mu[r] - mu[l - 1] ) * (a / l) * (b / l); } printf("%lld\n",ans); } }