zoukankan      html  css  js  c++  java
  • 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 ;
    }
    
  • 相关阅读:
    Qt CheckBox选中与未选中的使用
    Qt Excel表格宽高的设置
    VTK三维重建 使用VTK读取DICOM,并动态输出
    VC++ VTK 读取序列CT图片三维重建
    VTK 读取序列图像
    Qt QWidget提升QVTKWidget
    ITK 介绍
    Qt QMainWindow中利用多个QDockWidget构成标签页tab || tabifyDockWidget
    Qt QDockWidget属性 setFeatures、setAllowedAreas
    Qt Designer中toolBar的allowedAreas属性
  • 原文地址:https://www.cnblogs.com/Soulist/p/13783149.html
Copyright © 2011-2022 走看看