题面
题意
有n个男孩,m个女孩,他们中有些人高兴,其他人不高兴,第 i i i天,第 i m o d    n i\mod n imodn个男孩会和第 i m o d    m i\mod m imodm个女孩约会,若两人中有一个人高兴,则两个人都会高兴,则至少几天后,所有人都会高兴。
做法
首先可以将所有人根据模
gcd
(
n
,
m
)
\gcd(n,m)
gcd(n,m)值分成
gcd
(
n
,
m
)
\gcd(n,m)
gcd(n,m)组,不难发现如果某一组中一个高兴的人都没有,必然无解,然后分别计算每组的答案取最大值即可,现在考虑如何计算每组的答案。
可以发现如果第i个男孩高兴了,那么在m时刻后,第
(
i
+
m
)
m
o
d
  
n
(i+m)\mod n
(i+m)modn个男孩也会高兴。同理,如果第i个女孩高兴,在n时刻后,第
(
i
+
n
)
m
o
d
  
m
(i+n)\mod m
(i+n)modm个女孩也会高兴。同样,如果第x个女孩初始高兴,那么第
x
m
o
d
  
n
x\mod n
xmodn个男孩在第x时刻就会高兴,在m时刻后,第
(
x
+
m
)
m
o
d
  
n
(x+m)\mod n
(x+m)modn个男孩也会高兴。我们可以只考虑男孩对男孩的贡献,女孩对女孩的贡献,和前
max
(
n
,
m
)
\max(n,m)
max(n,m)时刻中男女孩之间的贡献。可以发现这三种贡献包含了所有贡献。
对这三种贡献考虑建图,用最短路求解,第i个男孩向第
(
i
+
m
)
m
o
d
  
n
(i+m)\mod n
(i+m)modn个男孩连权值为m的边,女孩同理,新建源点向初始高兴的点连权值为该点编号的边,若第i个男孩初始高兴,则向第
i
m
o
d
  
m
i\mod m
imodm个女孩连权值为0的边,女孩的连边同理,可以发现这张图从源点出发,到初始不高兴的人所对应的点的最短路的最大值即为答案。
现在考虑去掉一些点,可以发现对于所有初始高兴的男孩u(现在若相同编号的女孩初始高兴,也把该男孩看作初始高兴),最短路的最大值只有可能是点
(
u
−
m
)
m
o
d
  
n
(u-m)\mod n
(u−m)modn,也就是向初始高兴的男孩连边的男孩,因为男孩间的连边恰好构成了一个环,女孩也同理,所以可以只保留这些点和初始高兴的人对应的点,这样点数就只于初始高兴的人数有关了。
对于求男孩u到v的距离,可以发现就等价于求满足方程
x
∗
m
+
k
∗
n
=
v
−
u
x*m+k*n=v-u
x∗m+k∗n=v−u的最小非负整数x,可以先用扩展欧几里得算法求出方程
x
∗
m
+
y
∗
n
=
1
x*m+y*n=1
x∗m+y∗n=1的一组解,然后就能快速求两男孩或两女孩间的距离。
代码
#include<bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N 800100
using namespace std;
ll n,m,x,y,g,ans,tt,bb,dd,st,first[N],dn[N],len[N],d[N];
bool in[N],ok[N];
struct Bn
{
ll to,next,quan;
}bn[N<<1];
queue<ll>que;
vector<ll>a[N],b[N];
unordered_map<ll,ll>mm[2],use;
ll eg(ll u,ll v,ll &x,ll &y)
{
if(!v)
{
x=1,y=0;
return u;
}
ll res=eg(v,u%v,x,y);
x=x-u/v*y,swap(x,y);
return res;
}
inline void add(ll u,ll v,ll w)
{
bb++;
bn[bb].to=v;
bn[bb].next=first[u];
bn[bb].quan=w;
first[u]=bb;
}
inline ll disa(ll u,ll v){return y*(((v-u)%n+n)%n/g)%(n/g)*m;}
inline ll disb(ll u,ll v){return x*(((v-u)%m+m)%m/g)%(m/g)*n;}
inline bool cmpa(ll u,ll v){return disa(st,u)<disa(st,v);}
inline bool cmpb(ll u,ll v){return disb(st,u)<disb(st,v);}
inline ll zh(bool u,ll v){if(mm[u].count(v)) return mm[u][v];len[++tt]=v;return mm[u][v]=tt;}
inline ll calc(ll u)
{
sort(a[u].begin(),a[u].end()),sort(b[u].begin(),b[u].end());
tt=1,bb=0,mm[0].clear(),mm[1].clear();
ll i,j,p,q,t,res=0;
dd=0,use.clear();
for(i=0;i<a[u].size();i++) dn[++dd]=a[u][i],add(zh(0,a[u][i]),zh(1,a[u][i]%m),0),use[a[u][i]]=1,ok[zh(0,a[u][i])]=1;
for(i=0;i<b[u].size();i++) if(!use.count(b[u][i]%n)) dn[++dd]=b[u][i],use[b[u][i]%n]=1;
st=dn[1],sort(dn+1,dn+dd+1,cmpa);
for(i=1;i<=dd;i++)
{
p=zh(0,dn[i]%n),q=zh(0,dn[i%dd+1]%n);
add(1,p,dn[i]);
add(p,q,disa(dn[i]%n,dn[i%dd+1]%n));
q=zh(0,((dn[i%dd+1]-m)%n+n)%n);
if(p!=q) add(p,q,disa(dn[i],((dn[i%dd+1]-m)%n+n)%n));
}
dd=0,use.clear();
for(i=0;i<b[u].size();i++) dn[++dd]=b[u][i],add(zh(1,b[u][i]),zh(0,b[u][i]%n),0),use[b[u][i]]=1,ok[zh(1,b[u][i])]=1;
for(i=0;i<a[u].size();i++) if(!use.count(a[u][i]%m)) dn[++dd]=a[u][i],use[a[u][i]%m]=1;
st=dn[1],sort(dn+1,dn+dd+1,cmpb);
for(i=1;i<=dd;i++)
{
p=zh(1,dn[i]%m),q=zh(1,dn[i%dd+1]%m);
add(1,p,dn[i]);
add(p,q,disb(dn[i]%m,dn[i%dd+1]%m));
q=zh(1,((dn[i%dd+1]-n)%m+m)%m);
if(p!=q) add(p,q,disb(dn[i],((dn[i%dd+1]-n)%m+m)%m));
}
d[1]=0;
que.push(1);
for(;!que.empty();)
{
q=que.front();
que.pop();
in[q]=0;
for(p=first[q];p!=-1;p=bn[p].next)
{
t=bn[p].to;
if(d[t]<=d[q]+bn[p].quan) continue;
d[t]=d[q]+bn[p].quan;
if(!in[t])
{
in[t]=1;
que.push(t);
}
}
}
for(i=1;i<=tt;i++) if(!ok[i]) res=max(res,d[i]);
for(i=1;i<=tt;i++) first[i]=-1,d[i]=INF,ok[i]=0;
return res;
}
int main()
{
memset(first,-1,sizeof(first));
memset(d,0x3f,sizeof(d));
ll i,j,p,q;
cin>>n>>m;
g=eg(n,m,x,y);
if(g>200000)
{
puts("-1");
return 0;
}
p=m/g,q=n/g;
x=(x%p+p)%p;
y=(y%q+q)%q;
cin>>p;for(i=1;i<=p;i++) scanf("%lld",&q),a[q%g].push_back(q);
cin>>p;for(i=1;i<=p;i++) scanf("%lld",&q),b[q%g].push_back(q);
for(i=0;i<g;i++)
{
if(!a[i].size() && !b[i].size())
{
puts("-1");
return 0;
}
ans=max(ans,calc(i));
}
cout<<ans;
}