【bzoj2301】 HAOI2011—Problem b
http://www.lydsy.com/JudgeOnline/problem.php?id=2301 (题目链接)
题意
给出${a,b,c,d,k}$,${n}$组询问,求$${\sum_{i=a}^{b}\sum_{j=c}^{d} [gcd(i,j)=k]}$$
Solution
莫比乌斯反演,就是一堆公式推啊推。
运用容斥,那么答案就变成了:$${\sum_{i=1}^{b}\sum_{j=1}^{d} [gcd(i,j)=k]-\sum_{i=1}^{b}\sum_{j=1}^{c-1} [gcd(i,j)=k]-\sum_{i=1}^{a-1}\sum_{j=1}^{d} [gcd(i,j)=k]+\sum_{i=1}^{a-1}\sum_{j=1}^{c-1} [gcd(i,j)=k]}$$
这${4}$项都长得差不多,我们考虑其一般情况。
\begin{aligned} & \sum_{i=1}^{n}\sum_{j=1}^{m} [gcd(i,j)=k] \\ =&\sum_{i=1}^{\lfloor{n/k}\rfloor}\sum_{j=1}^{\lfloor{m/k}\rfloor} [gcd(i,j)=1] \\ =&\sum_{t=1}^{n}μ(t)\lfloor\frac{n}{kt}\rfloor\lfloor\frac{m}{kt}\rfloor \end{aligned}
于是我们就可以${O(n)}$的计算这个东西了,然而还不够。考虑到${\lfloor\frac{n}{kt}\rfloor}$和${\lfloor\frac{m}{kt}\rfloor}$的取值各有${2\sqrt{n},2\sqrt{m}}$种,所以我们对${μ(t)}$分段求前缀和。代码很好写。
细节
LL
代码
// bzoj2301 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<vector> #include<cmath> #define LL long long #define inf 2147483640 #define Pi acos(-1.0) #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); using namespace std; const int maxn=1000010; int p[maxn],vis[maxn],mu[maxn],s[maxn],a,b,c,d,K; LL solve(int n,int m) { n/=K,m/=K; if (n>m) swap(n,m); LL res=0; for (int i=1,j;i<=n;i=j+1) { //区间[i,j] j=min(n/(n/i),m/(m/i)); res+=(LL)(n/i)*(m/i)*(s[j]-s[i-1]); } return res; } int main() { int T;scanf("%d",&T); s[1]=mu[1]=1; for (int i=2;i<maxn;i++) { if (!vis[i]) p[++p[0]]=i,mu[i]=-1; for (int j=1;j<=p[0] && i*p[j]<maxn;j++) { vis[i*p[j]]=1; if (i%p[j]==0) {mu[i*p[j]]=0;break;} else mu[i*p[j]]=-mu[i]; } s[i]=s[i-1]+mu[i]; } while (T--) { scanf("%d%d%d%d%d",&a,&b,&c,&d,&K); printf("%lld\n",solve(b,d)-solve(b,c-1)-solve(a-1,d)+solve(a-1,c-1)); } return 0; }