【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;
}

 

posted @ 2017-02-04 10:11  MashiroSky  阅读(...)  评论(...编辑  收藏