luogu P2522 [HAOI2011]Problem b

题目链接

(sumlimits_{i=x}^nsumlimits_{j=y}^m [(i,j)=k])

根据容斥原理,可以把原始拆成形式相同的四个柿子进行计算。(以下均假设 (n<m),且所有除法均为下取整)

[egin{aligned} sumlimits_{i=1}^nsumlimits_{j=1}^m [(i,j)=k]&=sumlimits_{i=1}^{n/k}sumlimits_{j=1}^{m/k}[(i,j)=1] \&=sumlimits_{i=1}^{n/k}sumlimits_{j=1}^{m/k}sumlimits_{p|i,j}mu(p) \&=sumlimits_{p=1}^{n/k}mu(p)lfloor frac{n}{pk} floorlfloorfrac{m}{pk} floor end{aligned} ]

直接数论分块即可。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>

using namespace std;

const int N=50000;
int A,B,C,D,k;
int a[N+9],p[N+9],cnt,u[N+9];

void prime()
{
	u[1]=1;
	for (int i=2;i<=N;i++)
	{
		if(!a[i])
			a[i]=i,p[++cnt]=i,u[i]=-1;
		for (int j=1;j<=cnt;j++)
		{
			if(p[j]>N/i||p[j]>a[i])
				break;
			a[p[j]*i]=p[j];
			if(i%p[j])
				u[p[j]*i]=u[i]*u[p[j]];
		}
	}
	for (int i=1;i<=N;i++)
		u[i]+=u[i-1];
}

int calc(int A,int B)
{
	A=A/k,B=B/k;
	int Min=min(A,B),ans=0;
	for (int i=1;i<=Min;i++)
	{
		int j=(A/(A/i)),k=(B/(B/i)),l=min(j,k);
		ans+=(A/i)*(B/i)*(u[l]-u[i-1]);
		i=l;
	}
	return ans;
}

void init()
{
	scanf("%d %d %d %d %d",&A,&B,&C,&D,&k);
}

void work()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		init();
		printf("%d
",calc(B,D)-((calc(A-1,D)+calc(B,C-1)-calc(A-1,C-1))));
	}
}

int main()
{
	prime();
	work();
	return 0;
}

原文地址:https://www.cnblogs.com/With-penguin/p/13688383.html