CF516E Drazil and His Happy Friends

CF516E Drazil and His Happy Friends [* hard]

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

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

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

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

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

(n,mle 10^9,r,ble 10^5)

Solution

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

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

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

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

仅考虑男生的情况下,假设初始男生 (i) 快乐了,那么女生 (imod 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) 天后快乐。

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

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

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

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

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

于是这张图是一张大环。

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

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

然后特判一下非法的情况即可,算 (kcdot mmod 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 ;
}
原文地址:https://www.cnblogs.com/Soulist/p/13783149.html