• Codeforces 516E


    Codeforces 题面传送门 & 洛谷题面传送门

    首先思考一个非常简单的性质:记 (d=gcd(n,m)),那么每次在一起吃完饭的男女孩编号必定与 (d) 同余,而根据斐蜀定理可以得到另一方面的结论:对于每一个 (mod d) 的剩余类,如果其中至少有一个男孩/女孩是快乐的,那所有与这样的男孩/女孩编号 (mod d) 同余的男孩/女孩最终都会变得快乐。

    这样 (-1) 的情况就很好判断了:只要检查每个 (mod d) 的剩余类都至少有一个男孩/女孩是快乐的即可,特别地,如果 (d>b+g) 那答案肯定是 (-1),而显然要解决答案不是 (-1) 的情况,只需要对每个 (mod d) 的剩余类 (x) 都做一遍 (n,m) 的互质的情况,设其答案为 (ans),然后令答案对 (ans imes d+x)(max) 即可。

    考虑如何解决 (n,m) 互质的情况,考虑同余最短路(怎么想到的/bx,实是神仙),我们考虑这样建图:

    • 对于每个快乐的男孩 (b),连一条 (S o b),权值为 (b) 的边。
    • 对于每个快乐的女孩 (g),连一条 (S o gmod n),权值为 (g) 的边,表示这个女孩 (g) 最早会在 (g) 时刻带动男孩 (gmod n) 变得快乐。
    • 对于每个男孩 (i),连边 (i o(i+m)mod n),权值为 (m),表示如果 (i) 变得快乐,那么 (m) 时间以后 ((i+m)mod n) 也会变得快乐。

    跑最短路即可,最后我们取源点到所有一开始不快乐的男孩距离的最大值,就是所有男孩变得快乐的时间的最大值,然后再对所有女孩做一遍同样的操作即可。

    直接建图跑 dijkstra 复杂度是 (nlog n) 的,无法通过。我们发现第三类边构成了一个环,因此这个模型可以视作一个环上加了一些源点连到环上某个点的边,要求源点到所有非关键点的距离最大值,而关键点个数很小,因此我们考虑将关键点压进一个 set,然后对于两个相邻关键点 (l,r) 路径上的所有点,显然到源点距离最大的肯定是 (r-1),因此我们 (mathcal O(k)) 地算出所有这样的 (r-1) 到源点的距离,然后取 (max) 即可,这样复杂度就降到了 (klog k),其中 (k) 为关键点个数。

    #include <bits/stdc++.h>
    using namespace std;
    #define fi first
    #define se second
    #define fill0(a) memset(a,0,sizeof(a))
    #define fill1(a) memset(a,-1,sizeof(a))
    #define fillbig(a) memset(a,63,sizeof(a))
    #define pb push_back
    #define ppb pop_back
    #define mp make_pair
    #define mt make_tuple
    #define eprintf(...) fprintf(stderr,__VA_ARGS__)
    template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
    template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
    typedef pair<int,int> pii;
    typedef long long ll;
    typedef unsigned int u32;
    typedef unsigned long long u64;
    typedef long double ld;
    namespace fastio{
    	#define FILE_SIZE 1<<23
    	char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
    	inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
    	inline void putc(char x){(*p3++=x);}
    	template<typename T> void read(T &x){
    		x=0;char c=getchar();T neg=0;
    		while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
    		while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
    		if(neg) x=(~x)+1;
    	}
    	template<typename T> void recursive_print(T x){return (!x)?void():(recursive_print(x/10),putc(x%10^48),void());}
    	template<typename T> void print(T x){(!x)&&(putc('0'),0);(x<0)&&(putc('-'),x=~x+1);recursive_print(x);}
    	template<typename T> void print(T x,char c){print(x);putc(c);}
    	void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
    }
    const int MAXN=2e5;
    const ll INFll=0x3f3f3f3f3f3f3f3fll;
    int n,m,B,G,N,M;
    vector<int> b[MAXN+5],g[MAXN+5];
    int gcd(int x,int y){return (!y)?x:gcd(y,x%y);}
    void exgcd(int x,int y,int &a,int &b){
    	if(!y) return a=1,b=0,void();exgcd(y,x%y,a,b);
    	int tmp=a;a=b;b=tmp-(x/y)*b;
    }
    int getinv(int a,int mod){
    	int x,y;exgcd(a,mod,x,y);
    	return (x+mod)%mod;
    }
    ll solve(vector<int> &b,vector<int> &g,int n,int m){
    	map<int,bool> in;map<int,int> dis;set<int> pos;
    	for(int x:b){in[x]=1;pos.insert(x);dis[x]=x;}
    	for(int x:g){
    		pos.insert(x%n);
    		if(!dis.count(x%n)) dis[x%n]=x%n;
    		else chkmin(dis[x%n],x%n);
    	} int iv=getinv(m,n);
    	vector<pair<int,pii> > vec;int pos0=(*pos.begin());
    	for(int p:pos) vec.pb(mp(1ll*(p-pos0)*iv%n,mp(dis[p],in[p])));
    	vec.pb(mp(n,mp(0,1)));sort(vec.begin(),vec.end());ll mx=-1;
    //	for(int i=0;i<vec.size();i++) printf("%d %d %d
    ",vec[i].fi,vec[i].se.fi,vec[i].se.se);
    //	printf("
    ");
    	for(int i=1;i<vec.size();i++) if(!vec[i-1].se.se||vec[i].fi!=vec[i-1].fi+1)
    		chkmax(mx,1ll*(vec[i].fi-vec[i-1].fi-1)*m+vec[i-1].se.fi);
    //	printf("%d
    ",mx);
    	return mx;
    }
    int main(){
    	scanf("%d%d",&n,&m);int d=gcd(n,m);N=n/d;M=m/d;
    	if(d>MAXN) return puts("-1"),0;
    	scanf("%d",&B);for(int i=1,x;i<=B;i++) scanf("%d",&x),b[x%d].pb(x/d);
    	scanf("%d",&G);for(int i=1,x;i<=G;i++) scanf("%d",&x),g[x%d].pb(x/d);
    	for(int i=0;i<d;i++) if(b[i].empty()&&g[i].empty()) return puts("-1"),0;
    	ll res=0;
    	for(int i=0;i<d;i++){
    		chkmax(res,1ll*d*solve(b[i],g[i],N,M)+i);
    		chkmax(res,1ll*d*solve(g[i],b[i],M,N)+i);
    	} printf("%lld
    ",res);
    	return 0;
    }
    
  • 相关阅读:
    计算机网络概述
    虚拟机网卡配置
    元类
    反射和内置方法
    面向对象的三大特性
    MYSQL中EXISTS的用法
    Guava中的常见集合操作用法
    集合操作交并补的三种Java实现
    P9 get和resize操作(Java 13)
    P8 Java 13中 HashMap的 put方法
  • 原文地址:https://www.cnblogs.com/ET2006/p/Codeforces-516E.html
Copyright © 2020-2023  润新知