洛谷P2522 [HAOI2011]問題b

タイトルリンク

タイトル

\(n \)グループに尋ねられ、毎回\(a、b、c、d、k \)を与え\(\ sum \ limits_ {x = a} ^ {b} \ sum \ limits_ {y = c} ^ {d} [\ gcd(x、y)= k] \)

アイデア

包含と除外の原理+数論ブロック+メビウス反転

私が作ったメビウス反転の最初の質問==

\(f(n、m)= \ sum \ limits_ {i = 1} ^ {n} \ sum \ limits_ {j = 1} ^ {m} [\ gcd(i、j)= k] \)

次に、許容範囲と除外の原則に従って、問題の式は\(f(b、d)-f(b、c-1)-f(a-1、d)+ f(a-1、c- 1)\)

したがって、次の質問は\(f \)のを見つける方法です。

では\(f \)の値を単純化しましょう

  1. 元の数式は$$ \ sum \ limits_ {i = 1} ^ {\ lfloor \ frac {n} {k} \ rfloor} \ sum \ limits_ {j = 1} ^ {\ lfloor \ frac {と同等であると簡単に結論できます。 m} {k} \ rfloor} [\ gcd(i、j)= 1] $$

  2. 以降| \(N- \ MU(D)= [N- = 1] \ \イプシロン(N)= \ SUM \ limits_ {D}) それによって元の式に

\ [\ sum \ limits_ {i = 1} ^ {\ lfloor \ frac {n} {k} \ rfloor} \ sum \ limits_ {j = 1} ^ {\ lfloor \ frac {m} {k} \ rfloor} \ sum \ limits_ {d | gcd(i、j)} \ mu(d)\]

  1. 列挙オブジェクトを変更して列挙順序を変更するには、最初に\(d \)を列挙してから、

\ [\ sum \ limits_ {d = 1} ^ {\ min(n、m)} \ mu(d)\ sum \ limits_ {i = 1} ^ {\ lfloor \ frac {n} {k} \ rfloor} [d | i] \ sum \ limits_ {j = 1} ^ {\ lfloor \ frac {m} {k} \ rfloor} [d | j] \]

つまり、\(d | i \)および\(d | j \)の場合、\(d | \ gcd(i、j)\)

  1. 容易に入手可能な\(1 \ SIM \ lfloor \ FRAC {n}は{K} \ rfloor \) の合計\(\ lfloor \ FRAC {N } {DK} \ rfloor \) \(D \)同一の複数リー\(1 \ SIM \ lfloor \ FRAC {M} {K} \ rfloor \) の合計(\ lfloor \ FRAC {M \ } {DK} \ rfloor \) \(D \)倍、元のように式は$$ \ sum \ limits_ {d = 1} ^ {\ min(n、m)} \ mu(d)\ lfloor \ frac {n} {dk} \ rfloor \ lfloor \ frac {m} {dk } \ rfloor $$

現時点では\(O(n)\)で解くことができますが、同じ値を持つ間隔が多いため合格できません。そのため、数論を使用してブロックできます。

最初に前処理\(\ mu \)、次に数論を使用してブロックし、複雑さ\(O(n + T \ sqrt n)\)

私のコードは毎回形而上学を評価し、評価マシンの気分を見て、書くことをお勧めします

コード

/*
Author:loceaner
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e6 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, a, b, c, d, k, cnt, p[A], mu[A], sum[A];
bool vis[A];

void getmu() {
	int MAX = 50010;
	mu[1] = 1;
	for (int i = 2; i <= MAX; i++) {
		if (!vis[i]) mu[i] = -1, p[++cnt] = i;
		for (int j = 1; j <= cnt && i * p[j] <= MAX; j++) {
			vis[i * p[j]] = true;
			if (i % p[j] == 0) break;
			mu[i * p[j]] -= mu[i];
		}
	}
	for (int i = 1; i <= MAX; i++) sum[i] = sum[i - 1] + mu[i];
}

int work(int x, int y) {
	int ans = 0ll;
	int max = min(x, y);
	for (int l = 1, r; l <= max; l = r + 1) {
		r = min(x / (x / l), y / (y / l));
		ans += (1ll * x / (l * k)) * (1ll * y / (l * k)) * 1ll * (sum[r] - sum[l - 1]); 
	}
	return ans;
}

void solve() {
	a = read(), b = read(), c = read(), d = read(), k = read();
	cout << work(b, d) - work(a - 1, d) - work(b, c - 1) + work(a - 1, c - 1) << '\n';
}

signed main() {
	getmu();
	int T = read();
	while (T--) solve();
	return 0;
}

おすすめ

転載: www.cnblogs.com/loceaner/p/12717450.html