CF516E Drazil and His Happy Friends 题解

题目传送门

\(d=\gcd(n,m)\),发现只有编号在模 \(d\) 意义下相同的人之间会产生影响,那么有解当且仅当每个剩余系内有至少一个人是快乐的。所以在 \(d>b+g\) 时直接输出 -1 即可。

对于剩下的情况,先令 \(n\leftarrow \frac n d,m\leftarrow \frac m d\),如果 \(n<m\) 那么把男女交换一下。考虑对每个剩余系分别算出最小的天数,最后再对 \(ans\times d+i\) 取个最大值即为答案。

对于一个剩余系,如果所有男女编号组成的集合大小等于 \(n\),那么它的答案一定 \(\le n\),可以直接求出来,先特判掉这种情况。那么对于剩下的情况,如果某一时刻男生全都是快乐的,所有人就都是快乐的,因为对于最后的 \(m\) 天,每个女生都恰好跟一个男生玩。

考虑求出使所有男生变快乐的最小天数。对于每个快乐的女生,将其编号对应的男生也标成快乐。如果编号为 \(i\) 的男生在第 \(t\) 天变快乐,那么编号为 \((i+m)\bmod n\) 的男生就会在第 \(t+m\) 天变快乐。考虑建一个图,对于每一个点 \(i\) 连一条边 \(i\xrightarrow{m} (i+m)\bmod n\) 连一条边,因为 \(\gcd(n,m)=1\),所以这个图形成了一个环。再对每个快乐的男生 \(i\) 连一条边 \(S\xrightarrow{i} i\),那么答案就是点 \(S\) 到每个点的最短距离的最大值。

对于每个快乐的男生求出从点 \(0\) 到他所经过的边的数量,按这个值将所有男生排序。

因为点 \(S\) 到男生 \(i\) 的最短距离不一定为 \(i\),所以要先更新两遍,每次枚举每个男生用他当前的最短距离更新环上下一个快乐的男生的最短距离,然后就得到了真正的最短距离。

记点 \(S\) 到男生 \(i\) 的距离为 \(d_i\),点 \(0\) 到他的距离为 \(p_i\),环上的下一个男生编号为 \(j\),那么该同余系的答案就是 \(\max_{i,j}\{d_i+((p_j-p_i)\bmod n-1)\cdot m\}\)。最后所有同余系的 \(ans\times d+i\)\(i\) 是余数)取个最大值即可。

时间复杂度 \(\mathcal{O}((b+g)\log(b+g))\)

参考代码:

#include<bits/stdc++.h>
#define ll long long
#define mxn 200003
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rept(i,a,b) for(int i=a;i<b;++i)
using namespace std;
int n,m,g,t1,t2,t,p[mxn],d[mxn],p1[mxn],p2[mxn];
set<int>st[mxn];
set<pair<int,int>>s;
vector<int>d1[mxn],d2[mxn];
bool v1[mxn],v2[mxn];
ll ans;
int exgcd(int a,int b,int &x,int &y){
	if(b==0){x=1,y=0;return a;}
	int d=exgcd(b,a%b,y,x);y-=x*(a/b);
	return d;
}
signed main(){
	scanf("%d%d",&n,&m);
	scanf("%d",&t1);
	rep(i,1,t1)scanf("%d",&p1[i]);
	scanf("%d",&t2);
	rep(i,1,t2)scanf("%d",&p2[i]);
	if(n<m)swap(n,m),swap(t1,t2),swap(p1,p2);
	g=__gcd(n,m);
	if(g>t1+t2){
		puts("-1");
		return 0;
	}
	rep(i,1,t1)st[p1[i]%g].insert(p1[i]/g),d1[p1[i]%g].pb(p1[i]/g);
	rep(i,1,t2)st[p2[i]%g].insert(p2[i]/g),d2[p2[i]%g].pb(p2[i]/g);
	n/=g,m/=g;
	int x,y;exgcd(n,m,x,y);
	y=(y%n+n)%n;
	rept(i,0,g){
		if(st[i].empty()){
			puts("-1");
			return 0;
		}
		if(st[i].size()==n){
			rept(j,0,n)v1[j]=v2[j]=0;
			for(int j:d1[i])v1[j]=1;
			for(int j:d2[i])v2[j]=1;
			ll mx=-1;
			rept(j,0,n)if(!v1[j]||!v2[j%m])mx=j,v1[j]=v2[j%m]=1;
			ans=max(ans,mx*g+i);
			continue;
		}
		s.clear();
		t=0;
		for(int j:st[i])s.insert({(ll)j*y%n,j});
		for(auto it:s)p[++t]=it.first,d[t]=it.second;
		rep(i,2,t)d[i]=min((ll)d[i],d[i-1]+(ll)m*(p[i]-p[i-1]));
		d[1]=min((ll)d[1],d[t]+(ll)m*(p[1]-p[t]+n));
		rep(i,2,t)d[i]=min((ll)d[i],d[i-1]+(ll)m*(p[i]-p[i-1]));
		d[1]=min((ll)d[1],d[t]+(ll)m*(p[1]-p[t]+n));
		ll mx=d[t]+(ll)(p[1]-p[t]+n-1)*m;
		rep(i,2,t)mx=max(mx,d[i-1]+(ll)(p[i]-p[i-1]-1)*m);
		ans=max(ans,mx*g+i);
	}
	cout<<ans;
	return 0;
}
posted @ 2024-02-24 17:43  zifanwang  阅读(7)  评论(0)    收藏  举报  来源