[HAOI2011] Problem b

前言

update 2022.1.22 血压升高,之前写的题解竟然是错的!

板题一号

题目

洛谷

题意:

\(\sum_{i=a}^b\sum_{j=c}^d[\gcd(i,j)=k]\)

讲解

大方向为容斥

\(S(n,m)=\sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=k]\)

则原式可化为 \(S(b,d)-S(a-1,d)-S(b,c-1)+S(a-1,c-1)\)

\(f(k)=\sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=k]\),即 \(S(n,m)\)

\(F(k)=\sum_{k|d}f(d)=\lfloor\dfrac{n}{k}\rfloor\lfloor\dfrac{m}{k}\rfloor\)

\(f(k)=\sum_{k|d}\mu(\dfrac{d}{k})F(d)=\sum_{k|d}\mu(\dfrac{d}{k})\lfloor\dfrac{n}{d}\rfloor\lfloor\dfrac{m}{d}\rfloor\)

我们将 \(\dfrac{d}{k}\) 换元,得到:

\(f(k)=\sum_{i=1}^{\frac{\min(n,m)}{k}}\mu(i)\lfloor\dfrac{n}{ik}\rfloor\lfloor\dfrac{m}{ik}\rfloor\)

然后数论分块即可

代码

//12252024832524
#include <cstdio>
#include <cstring>
#include <algorithm>
#define TT template<typename T>
using namespace std; 

typedef long long LL;
const int MAXN = 50005;
int n,k;

LL Read()
{
	LL x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}

int prime[MAXN],pn,mu[MAXN],pre[MAXN];
bool vis[MAXN];
void sieve(int x)
{
	pre[1] = mu[1] = 1;
	for(int i = 2;i <= x;++ i)
	{
		if(!vis[i]) mu[i] = -1,prime[++pn] = i;
		for(int j = 1;j <= pn && i * prime[j] <= x;++ j)
		{
			vis[i*prime[j]] = 1;
			if(i % prime[j] == 0) break;
			mu[i*prime[j]] = -mu[i];
		}
		pre[i] = pre[i-1] + mu[i];
	}
}
int solve(int n,int m)
{
	if(n > m) swap(n,m);
	if(n <= 0) return 0;
	int ret = 0; n /= k; m /= k;
	for(int l = 1,r;l <= n;l = r+1)
	{
		r = Min(n/(n/l),m/(m/l));
		ret += (n / l) * (m / l) * (pre[r] - pre[l-1]);
	}
	return ret;
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	sieve(MAXN-5);
	for(int T = Read(); T ;-- T)
	{
		int a = Read(),b = Read(),c = Read(),d = Read(); k = Read();
		Put(solve(b,d)-solve(a-1,d)-solve(c-1,b)+solve(a-1,c-1),'\n');
	}
	return 0;
}
posted @ 2021-01-09 15:35  皮皮刘  阅读(66)  评论(0编辑  收藏  举报