Loading

CF516E 做题记录

link

纪念一下独立切的 *3100 的数论 + 贪心题,思考时的思路一波三折,像极了考试中的我。

个人感觉难度至少 *3300。

考虑先求出 \(d = \gcd(n, m)\),那么编号根据模 \(d\) 结果分成了 \(0...d-1\)\(d\) 个部分,每个部分里的人不能和外面的人玩。

因此当 \(d> b + g\) 时一定无解,接下来我们对 \(d\) 个部分分开处理。

我们考虑求出使得全部女生快乐的最小天数,求男生的天数只需要把两堆人对调。

考虑编号为 \(0\) 的男生,第一次和编号为 \(0\) 的女生玩,第二次和编号为 \(n\bmod m\) 的女生玩,第三次和编号为 \(2n\bmod m\) 的女生玩,以此类推。

那么我们把 \(0...m-1\) 建一个环,对于环上的一个点 \(u\),向 \((u+n) \bmod m\) 连边。

钦定环上一个点的 id 为从 \(0\) 开始走的步数,我们容易使用 exgcd 算出一个点的 id。

把所有快乐的女生编号对应的 id,以及快乐的男生编号 \(\bmod m\) 对应的 id 拎出来,排个序。

对于每个拎出来的点 \(u\),算出环上 id 为 \(u-1\) 的女生的答案,容易通过拎出来的前一个点算出,可以发现这考虑了所有女生的答案。

时间复杂度 \(O(n\log n)\)

点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define fi first
#define se second
#define pir pair <ll, ll>
#define mkp make_pair
#define pb push_back
using namespace std;
void read(ll &x) {
	char c; ll f = 1;
	while(!isdigit(c = getchar()))
		if(c == '-') f = -1;
	x = c - '0';
	while(isdigit(c = getchar())) x = x * 10 + c - '0';
	x *= f;
}
const ll maxn = 4e5 + 10, inf = 1e17;
ll nl, ml, n, m, g;
vector <ll> v1[maxn], v2[maxn];
ll ans;
void exgcd(ll a, ll b, ll &x, ll &y) {
	if(!b) {
		x = 1, y = 0;
		return;
	}
	exgcd(b, a%b, x, y);
	ll t = x;
	x = y, y = t - a / b * y;
}
ll Get(ll i) {
	ll x, y;
	exgcd(nl, ml, x, y);
	x *= i, y *= i;
	x = (x % ml + ml) % ml;
	return x;
}
ll iGet(ll i) {return i * nl % ml;}
ll h[maxn], ht, mn[maxn], vis[maxn];
void solve(ll u) {
	ht = 0;
	for(ll i: v1[u]) {
		ll x = i / g;
		ll id = Get(x % ml);
		h[++ht] = id;
	}
	for(ll i: v2[u]) {
		ll x = i / g;
		ll id = Get(x);
		h[++ht] = id;
	}
	if(!ht) {ans = inf; return;}
	sort(h + 1, h + 1 + ht);
	ht = unique(h + 1, h + 1 + ht) - h - 1;
	for(ll i = 1; i <= ht; i++)
		mn[i] = inf, vis[i] = 0;
	for(ll i : v1[u]) {
		ll x = i / g;
		ll id = Get(x % ml);
		ll Id = lower_bound(h + 1, h + 1 + ht, id) - h;
		mn[Id] = min(mn[Id], i);
	}
	for(ll i : v2[u]) {
		ll x = i / g;
		ll id = Get(x);
		ll Id = lower_bound(h + 1, h + 1 + ht, id) - h;
		mn[Id] = min(mn[Id], i), vis[Id] = 1;
	}
	for(ll i = 1; i <= ht; i++) {
		ll x = (h[i] + ml - 1) % ml, j = (i + ht - 2) % ht + 1;
		if(x == h[j] && vis[j]) continue; 
		ll ret = mn[j] + (x - h[j] + ml) % ml * nl * g;
		ans = max(ans, ret);
	}
}
int main() {
	read(nl), read(ml), read(n);
	g = __gcd(nl, ml);
	nl /= g, ml /= g;
	if(g > 2e5) {puts("-1"); return 0;}
	for(ll i = 1, x; i <= n; i++) {
		read(x);
		v1[x % g].pb(x);
	}
	read(m);
	for(ll i = 1, x; i <= m; i++) {
		read(x);
		v2[x % g].pb(x);
	}
	for(ll i = 0; i < g; i++) {
		sort(v1[i].begin(), v1[i].end());
		sort(v2[i].begin(), v2[i].end());
	}
	for(ll i = 0; i < g; i++)
		solve(i);
	for(ll i = 0; i < g; i++) swap(v1[i], v2[i]);
	swap(nl, ml);
	for(ll i = 0; i < g; i++)
		solve(i);
	if(ans == inf) ans = -1;
	printf("%lld", ans);
	return 0;
}
posted @ 2024-05-09 16:05  Sktn0089  阅读(21)  评论(0编辑  收藏  举报