CF516E Drazil and His Happy Friends

题意

有n个男孩,m个女孩。都分别从0开始标号。
初始分别有b个男孩和g个女孩是高兴的。第 t , t 0 t,t\geq0 天时,男孩 t m o d    n t\mod n 和女孩 t m o d    m t\mod m 会碰面并传递高兴状态。(也就是说,只要有一个人是高兴的,那么过完这天两个人都变得高兴)。
现在问,多少天之后所有人都变得高兴,或判断无解。
n , m 1 0 9 , b , g 1 0 5 n,m\leq 10^9,b,g\leq10^5

思路

  • g c d ( n , m ) = 1 gcd(n,m)=1 ,所有男孩与所有女孩都会碰面。此时是有解的。
  • 否则,根据一些exgcd的常识,不难发现只要根据模gcd的余数分类,不同类之间是没有影响的,并且每一类中依然是上述情况。
  • 因此,只要每一类中有至少一个高兴的人,就是有解的。问题变成了求每一类的最大答案。
  • 不妨先考虑女孩这边。此时另一边的作用就是传递高兴和给初始的高兴状态:
  1. 若时刻T时女孩y是高兴的,则时刻T+n时,女孩 ( y + n ) m o d    m (y+n)\mod m 会变得高兴。
  2. 若男孩x初始是高兴的,那么时刻T女孩 x m o d    m x\mod m 会变得高兴。
    初始高兴的男孩对其他女孩的贡献相当于利用他传递高兴,因此不需要考虑。
  • 这看起来就很图论了,建个有向图,连上对应的边跑最短路即可。
  • 虽然点数很多,但是这个图有很多度数为2的点(因为1类边实际上连出了一个环)。又由于所有边都是非负边,并且我们只需要最大的最短路。因此环上的一些无用点可以缩去。
  • 两两关键点之间的环长使用exgcd求得即可。

对男孩也做上述过程,这题就搞定了。
O ( ( b + g ) log ) O((b+g) \log)
(写的很丑…跑的很慢…)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int b, g, e, S;
ll n, m, len[N];
vector<ll> ori[N][2];

ll gcd(ll a, ll b) {
	return b == 0 ? a : gcd(b, a % b);
}

map<int,int> idx,idy;
int node_cnt;

ll exgcd(ll a, ll b, ll &x0, ll &y0) {
	if (b == 0) {
		x0 = 1, y0 = 0;
		return a;
	}
	ll x = 0, y = 0;
	ll z = exgcd(b, a % b, x, y);
	x0 = y;
	y0 = x - a / b * y;
	return z;
}

ll getdis(ll _a, ll _b, ll sz, ll len) { //x->(x+len)%sz
	//k1 * len + k2 * sz = b - a
	ll x = 0, y = 0, a = len, b = sz, c = _b - _a;
	ll g = exgcd(a, b, x, y);
	x = x * (c / g), y = y * (c / g);
	//调整成最小非负整数解
	ll o = b / g;
	x %= o;
	if (x < 0) x += o;
	// cerr << _a << " " << _b << " " << x * len << endl;
	return x * len;
}

vector<pair<int,ll>> edge[N * 8];
void link(int x, int y, ll len) {
	edge[x].push_back(make_pair(y, len));
}

ll dis[N * 8];
void dij() {
	memset(dis, 127, (node_cnt + 10) * 8);
	dis[S] = 0;
	static priority_queue<pair<ll,int>> pq;
	pq.push(make_pair(0, S));
	while(pq.size()) {
		int x = pq.top().second;
		ll le = pq.top().first;
		pq.pop();
		if (dis[x] != le) continue;
		for(pair<int,ll> e : edge[x]) {
			int y = e.first;
			if (dis[x] + e.second < dis[y]){
				dis[y] = dis[x] + e.second;
				pq.push(make_pair(dis[y], y));
			} 
		}
	}
}

int cs[N * 8];
ll getans(ll w) {
	node_cnt = 0;
	static vector<ll> impx, impy;
	impx = ori[w][0];
	impy = ori[w][1];
	for(int x : ori[w][0]) impy.push_back(x % m);
	for(int y : ori[w][1]) impx.push_back(y % n);
	for(int i = 0, ed = impx.size(); i < ed; i++) {
		impx.push_back(((impx[i] - m) % n + n) % n);
	}

	for(int i = 0, ed = impy.size(); i < ed; i++) {
		impy.push_back(((impy[i] - n) % m + m) % m);
	}

	sort(impx.begin(), impx.end());
	sort(impy.begin(), impy.end());
	impx.resize(unique(impx.begin(), impx.end()) - impx.begin());
	impy.resize(unique(impy.begin(), impy.end()) - impy.begin());
	//. Get all important points.
	
	S = ++node_cnt;
	idx.clear(), idy.clear();
	for(int x : impx) idx[x] = ++node_cnt;
	for(int y : impy) idy[y] = ++node_cnt;
	memset(cs, 0, 4 * (node_cnt + 5));
	//. number them.
	for(int i = 1; i <= node_cnt; i++) edge[i].clear();
	for(int x : ori[w][0]) {
		cs[idx[x]] = 1;
		link(S, idx[x], x), link(idx[x], idy[x % m], 0);
	}
	for(int y : ori[w][1]) {
		cs[idy[y]] = 1;
		link(S, idy[y], y), link(idy[y], idx[y % n], 0);
	}
	static vector<pair<ll,int>> cir; cir.clear();
	for(int x : impx) {
		cir.push_back(make_pair(getdis(impx.front(), x, n, m), x));
	}
	sort(cir.begin(), cir.end());
	pair<ll,int> las = make_pair(-1, -1);
	for(pair<ll,int> x : cir) {
		if (las.first != -1) {
			link(idx[las.second], idx[x.second], x.first - las.first);
		}
		las = x;
	}
	if (las.first!=-1)
		link(idx[las.second], idx[cir.front().second], getdis(las.second, cir.front().second, n, m));

	cir.clear();
	for(int y : impy) {
		cir.push_back(make_pair(getdis(impy.front(), y, m, n), y));
	}
	sort(cir.begin(), cir.end());
	las = make_pair(-1, -1);
	for(pair<ll,int> y : cir) {
		// cerr << y.second << " ";
		if (las.first != -1) {
			link(idy[las.second], idy[y.second], y.first - las.first);
		}
		las = y;
	}
	if (las.first!=-1)
		link(idy[las.second], idy[cir.front().second], getdis(las.second, cir.front().second, m, n));
	dij();
	ll ret = 0;
	for(int i = 1; i <= node_cnt; i++) if(!cs[i]) 
		ret = max(ret, dis[i]);
	return ret;
}

int main() {
	freopen("e.in","r",stdin);
	cin >> n >> m;
	e = gcd(n, m);
	if (e > 2e5) {
		printf("-1"); return 0;
	}
	cin >> b;
	for(int i = 1; i <= b; i++) {
		int t; scanf("%d", &t);
		ori[t % e][0].push_back(t);
	}
	cin >> g;
	for(int i = 1; i <= g; i++) {
		int t; scanf("%d", &t);
		ori[t % e][1].push_back(t);
	}
	for(int i = 0; i < e; i++) {
		if (ori[i][0].size() + ori[i][1].size() == 0) {
			printf("-1\n"); return 0;
		}
	}
	ll ans = 0;
	for(int i = 0; i < e; i++) {
		ans = max(ans, getans(i));
	}
	cout << ans << endl;
}

发布了266 篇原创文章 · 获赞 93 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/jokerwyt/article/details/103021688
今日推荐