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}$项都长得差不多,我们考虑其一般情况。
egin{aligned} & sum_{i=1}^{n}sum_{j=1}^{m} [gcd(i,j)=k] \ =&sum_{i=1}^{lfloor{n/k} floor}sum_{j=1}^{lfloor{m/k} floor} [gcd(i,j)=1] \ =&sum_{t=1}^{n}μ(t)lfloorfrac{n}{kt} floorlfloorfrac{m}{kt} floor end{aligned}
于是我们就可以${O(n)}$的计算这个东西了,然而还不够。考虑到${lfloorfrac{n}{kt} floor}$和${lfloorfrac{m}{kt} floor}$的取值各有${2sqrt{n},2sqrt{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 ",solve(b,d)-solve(b,c-1)-solve(a-1,d)+solve(a-1,c-1)); } return 0; }