AtCoder Regular Contest 123 F Insert Addition

发布时间 2023-09-28 15:59:16作者: zltzlt

洛谷传送门

AtCoder 传送门

\((x, y)\) 表示 \(Ax + By\),那么这个等价于 SB 树。

那么直接在 SB 树上二分,遍历一遍找到 \(n\) 个点就好了。可以采用类似线段树查询的方式。

于是现在还剩下一个子问题:给定 \(a, b\),求 \(ax + by \le n\)\(\gcd(x, y) = 1\) 的正整数 \((x, y)\) 对数。

考虑莫反,可得为 \(\sum\limits_{p = 1}^n \mu(p) \sum\limits_{x = 1}^{\left\lfloor\frac{n}{ap}\right\rfloor} \left\lfloor\frac{\left\lfloor\frac{n}{p}\right\rfloor - ax}{b}\right\rfloor\)

这个东西可以整除分块后类欧算。注意因为 \(-a\) 是负数,所以要变成 \((-a) \bmod b\),然后答案加上 \(\frac{n(n + 1)}{2} \times \frac{(-a) \bmod b - (-a)}{b}\)

理论时间复杂度其实是 \(O(n \sqrt{n} \log n)\),但是跑得挺快的。

code
// Problem: F - Insert Addition
// Contest: AtCoder - AtCoder Regular Contest 123
// URL: https://atcoder.jp/contests/arc123/tasks/arc123_f
// Memory Limit: 1024 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef __int128 lll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 300100;

ll A, B, n, L, R, pr[maxn], tot, mu[maxn];
bool vis[maxn];

namespace EL {
	struct node {
		ll cntx, cnty, sum;
		node(ll a = 0, ll b = 0, ll c = 0) : cntx(a), cnty(b), sum(c) {}
	};
	
	inline node operator + (const node &a, const node &b) {
		node res;
		res.cntx = a.cntx + b.cntx;
		res.cnty = a.cnty + b.cnty;
		res.sum = a.sum + b.sum + a.cnty * b.cntx;
		return res;
	}
	
	inline node qpow(node a, ll p) {
		node res;
		while (p) {
			if (p & 1) {
				res = res + a;
			}
			a = a + a;
			p >>= 1;
		}
		return res;
	}
	
	node solve(ll p, ll q, ll r, ll n, node a, node b) {
		if (!n) {
			return node();
		}
		if (p >= q) {
			return solve(p % q, q, r, n, a, qpow(a, p / q) + b);
		}
		ll cnt = ((lll)n * p + r) / q;
		if (!cnt) {
			return qpow(b, n);
		}
		return qpow(b, (q - r - 1) / p) + a + solve(q, p, (q - r - 1) % p, cnt - 1, b, a) + qpow(b, n - ((lll)q * cnt - r - 1) / p);
	}
	
	inline ll calc(ll p, ll q, ll r, ll n) {
		ll ans = 0;
		if (p < 0) {
			ll t = (p % q + q) % q;
			ans -= n * (n + 1) / 2 * ((t - p) / q);
			p = t;
		}
		node a(0, 1), b(1, 0);
		node res = qpow(a, r / q) + solve(p, q, r % q, n, a, b);
		ans += res.sum;
		return ans;
	}
}

inline ll calc(ll a, ll b) {
	ll ans = 0;
	for (int i = 1, j; i <= n; i = j + 1) {
		j = n / (n / i);
		ans += EL::calc(-a, b, n / i, n / a / i) * (mu[j] - mu[i - 1]);
	}
	return ans;
}

vector<ll> ans;

void dfs(int lx, int ly, int rx, int ry) {
	int mx = lx + rx, my = ly + ry;
	if (A * mx + B * my > n) {
		return;
	}
	dfs(lx, ly, mx, my);
	ans.pb(A * mx + B * my);
	dfs(mx, my, rx, ry);
}

void dfs(int lx, int ly, int rx, int ry, ll l, ll r) {
	if ((int)ans.size() >= R - L + 1) {
		return;
	}
	if (L <= l && r <= R) {
		dfs(lx, ly, rx, ry);
		ans.pb(A * rx + B * ry);
		return;
	}
	int mx = lx + rx, my = ly + ry;
	if (A * mx + B * my > n) {
		return;
	}
	ll t = l + calc(A * lx + B * ly, A * mx + B * my);
	if (L <= t) {
		dfs(lx, ly, mx, my, l, t);
	}
	if (t < R) {
		dfs(mx, my, rx, ry, t + 1, r);
	}
}

void solve() {
	scanf("%lld%lld%lld%lld%lld", &A, &B, &n, &L, &R);
	mu[1] = 1;
	for (int i = 2; i <= n; ++i) {
		if (!vis[i]) {
			pr[++tot] = i;
			mu[i] = -1;
		}
		for (int j = 1; j <= tot && i * pr[j] <= n; ++j) {
			vis[i * pr[j]] = 1;
			if (i % pr[j] == 0) {
				mu[i * pr[j]] = 0;
				break;
			}
			mu[i * pr[j]] = -mu[i];
		}
	}
	for (int i = 1; i <= n; ++i) {
		mu[i] += mu[i - 1];
	}
	ll t = calc(A, B) + 1;
	--R;
	if (L == 1) {
		ans.pb(A);
	} else {
		--L;
	}
	dfs(1, 0, 0, 1, 1, t);
	for (ll x : ans) {
		printf("%lld ", x);
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}