【Luogu P2522】 [HAOI2011]Problem b

题目链接:

题目

博客园

题目大意:

快速求:

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

正文:

这道题和 [POI2007]ZAP-Queries 思路一样,先化简再整除分块。但是这题不能直接化,先考虑 \(a=1,c=1\) 的情况,用二维前缀和的思想得到答案。

代码:


ll n, m, n1, m1, d, t;
ll pri[N], miu[N], cnt, sum[N];
bool vis[N];

void prework()
{
	miu[1] = 1;
	for (int i = 2; i <= N - 10; i++)
	{
		if(!vis[i]) {pri[++cnt] = i, miu[i] = -1;}
		for (int j = 1; j <= cnt && pri[j] * i <= N - 10; j++)
		{
			vis[pri[j] * i] = 1;
			if (i % pri[j] == 0)
			{
				miu[i * pri[j]] = 0;
				break;
			}
			else
				miu[i * pri[j]] = -miu[i];
		}
	}
	for (int i = 1; i <= N - 10; i++)
		sum[i] = sum[i - 1] + miu[i];
}
ll Ans(int n, int m)
{
	ll ans = 0;
	if(n > m)
	{
		int c = n; n = m; m = c;
	}
	n /= d, m /= d;
	for (int l = 1, r; l <= n; l = r + 1)
	{
		r = min (n / (n / l), m / (m / l));
		ans += (sum[r] - sum[l - 1]) * (n / l) * (m / l);
	}
	return ans;
}

int main()
{
	prework();
	for (scanf ("%lld", &t); t--; )
	{
		scanf("%lld%lld%lld%lld%lld", &n, &m, &n1, &m1, &d);
		printf("%lld\n", Ans(m, m1) - Ans(m, n1 - 1) - Ans(n - 1, m1) + Ans(n1 - 1, n - 1));
	}
	return 0;
}
posted @ 2020-09-02 19:18  Jayun  阅读(76)  评论(0编辑  收藏  举报