CF516E Drazil and His Happy Friends

CF516E Drazil and His Happy Friends [* hard]

给定 \(n,m\) 表示有 \(n\) 个 boy 和 \(m\) 个 girl,编号为 \(0\sim n-1,0\sim m-1\)

然后给出 \(r\) 个好的 boy 和 \(b\) 个好的 girl

对于第 \(i\) 天,我们将让编号为 \(i\mod n\) 的 boy 和 \(i\mod m\) 的 girl 玩耍。

如果有一个是好的,那么两个人就都会好。

求最少多少天可以使得所有人都好起来。

\(n,m\le 10^9,r,b\le 10^5\)

Solution

我们发现可以按照 \(\gcd(n,m)\) 进行等价类划分,这样我们得到了 \(\gcd(n,m)\) 个等价类,每个等价类对答案的影响都是独立的。

然后 \(\gcd(n,m)>b+g\) 时,那么一定是无解的,因为此时不是所有等价类内都有点。

方便起见接下来设 \(n,m\) 互质。

考虑对于每个等价类求解一组答案,考虑答案是男生中最后一个元素和女生中最后一个元素取 \(\min\) 的结果。

仅考虑男生的情况下,假设初始男生 \(i\) 快乐了,那么女生 \(i\mod m\) 一定会快乐,于是男生 \((i+m)\mod n\) 会在 \(m\) 天后快乐。

假设男生 \(i\) 快乐了,此时为女生 \(x\),那么 \(m\) 天后仍有 \((i+m)\mod n\) 会快乐。

基于一个这样的考虑,假设男生 \(i\) 快乐了,此时为女生 \(x\),那么 \(m\) 天后男生 \((i+m)\mod n\) 一定会快乐,同时 \(n\) 天后,女生 \((x+n)\mod m\) 一定会快乐,然后他会使得男生 \((i+n+m)\mod n\) 快乐,此时花费天数为 \(n+m\)

所以我们一定是 \(i\) 快乐后,通过对应女生,使得 \((i+m)\mod n\)\(m\) 天后快乐。

那么考虑同余最短路建图,令 \(i\xrightarrow{m} (i+m)\mod n\)

然后对于男生女生,都将 \(i\mod m\) 的初值设为 \(i\)

然后此时所有点的最短路的最大值即为答案。

等下 \(.~.~.~\rm 1e9~.~.~.\) 你说最短路?

由于我们观察到 \(m,n\) 互质,所以 \((i+m)\mod n\) 互不相同。(即 \(i+km\) 可以取遍 \(n\) 中所有点)

于是这张图是一张大环。

我们只需要保留拥有初值的点,然后找到一个顺序将他们串起来即可。

考虑将所有数 \(i\) 表示成 \(k\cdot m\mod n\),这样显然是按照 \(k\) 排序连边,然后两两之间对答案的贡献就是初值加上 \(k\) 的差乘以 \(m\)

然后特判一下非法的情况即可,算 \(k\cdot m\mod n=i\) 等价于 \(mx+ny=i\),exgcd 解一解即可。

复杂度是 \(\mathcal O((r+b)\log)\),exgcd 需要解的方程是相同的,所以预处理一下即可,复杂度瓶颈在排序和特判答案小于 \(\max(n, m)\) 的情况上。

记得特判不需要满轮就可以输出的情况。

\(Code:\)

#include<bits/stdc++.h>
using namespace std ;
#define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
#define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
#define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
#define re register
#define vi vector<int>
#define int long long
#define pb push_back
int gi() {
	char cc = getchar() ; int cn = 0, flus = 1 ;
	while( cc < '0' || cc > '9' ) {  if( cc == '-' ) flus = - flus ; cc = getchar() ; }
	while( cc >= '0' && cc <= '9' )  cn = cn * 10 + cc - '0', cc = getchar() ;
	return cn * flus ;
}
const int N = 2e5 + 5 ; 
int n, m, B, G, g[N], b[N], A[N], cnt, cnt1, cnt2, _a, _b, Ai, Bi ;
vi f[N], h[N] ; 
struct node {
	int d, c ; 
	node(int _d = 0, int _c = 0) { d = _d, c = _c ; }
} A1[N], A2[N] ;
void out() { puts("-1") ; exit(0) ; }
int gcd(int x, int y) { return (!y) ? x : gcd(y, x % y) ; }
int exgcd(int x, int y) {
	if(y == 0) { _a = 1, _b = 0 ; return x ; }
	int d = exgcd(y, x % y), ia = _b, ib = _a - (x / y) * _b ;
	_a = ia, _b = ib ; return d ; 
}
int Get(int x, int type) { 
	int fa = Ai * x, fb = Bi * x ; 
	fa %= m ; if( fa < 0 ) fa += m ;
	fb %= n ; if( fb < 0 ) fb += n ;
	return (type) ? fa : fb ; 
}
bool cmp(node x, node y) {
	return ( x.d == y.d ) ? (x.c > y.c) : (x.d < y.d) ; 
}
int Go(int x, int y, int mod) {//x to y mod m
	return (x < y) ? y - x - 1 : (mod - 1 - x + y) ;
}
map<int, int> m1, m2 ; 
int solve(int x) { 
	cnt = cnt1 = cnt2 = 0, m1.clear(), m2.clear() ; int ans = 0 ; 
	if( (f[x].size() == n) && (h[x].size() == m) ) return -1 ; 
	for(int v : f[x]) A[++ cnt] = v, m1[v] = 1 ; 
	for(int v : h[x]) A[++ cnt] = v, m2[v] = 1 ;
	for(int v : f[x]) if(!m2[v % m]) ans = max(ans, v), m2[v % m] = 1 ;
	for(int v : h[x]) if(!m1[v % n]) ans = max(ans, v), m1[v % n] = 1 ; 
	rep( i, 1, cnt ) 
		A1[++ cnt1] = node(Get(A[i], 0), A[i]), //0 mean k * m % n = x
		A2[++ cnt2] = node(Get(A[i], 1), A[i]) ; 
	sort(A1 + 1, A1 + cnt1 + 1, cmp), sort(A2 + 1, A2 + cnt2 + 1, cmp) ;
	A1[cnt1 + 1] = A1[1], A2[cnt2 + 1] = A2[1] ; 
	rep( i, 1, cnt1 ) {
		int dis = A1[i].c + Go(A1[i].d, A1[i + 1].d, n) * m ;
		if( (A1[i + 1].d - A1[i].d < 2) && (i != cnt1) ) continue ;  
		ans = max(ans, dis) ; 
	} 
	rep( i, 1, cnt2 ) {
		int dis = A2[i].c + Go(A2[i].d, A2[i + 1].d, m) * n ; 
		if( (A2[i + 1].d - A2[i].d < 2) && (i != cnt2) ) continue ;  
		ans = max(ans, dis) ; 
	} 
	return ans ; 
}
signed main()
{
	n = gi(), m = gi() ; int d = gcd(n, m) ; 
	B = gi() ; rep( i, 1, B ) b[i] = gi() ; sort(b + 1, b + B + 1) ;
	G = gi() ; rep( i, 1, G ) g[i] = gi() ; sort(g + 1, g + G + 1) ; 
	if( d > B + G ) out() ; int ans = 0 ;  
	n /= d, m /= d, exgcd(n, m), Ai = _a, Bi = _b, Ai %= m, Bi %= n ; 
	rep( i, 1, B ) f[b[i] % d].pb(b[i] / d) ; 
	rep( i, 1, G ) h[g[i] % d].pb(g[i] / d) ;
	rep( i, 0, d - 1 ) if(!f[i].size() && !h[i].size()) out() ; 
	rep( i, 0, d - 1 ) ans = max(ans, solve(i) * d + i) ; 
	cout << ans << endl ; 
	return 0 ;
}
posted @ 2020-10-08 22:51  Soulist  阅读(141)  评论(0编辑  收藏  举报