分别计算两侧点的最大时间,不妨考虑男生一侧。
某个一开始不开心的男生
x
x
x,如果他最后开心了,那么一定是由某个一开始开心的人传递过来的,假设那个人的编号是
s
s
s(在哪侧不重要),传到
x
x
x时间的下界显然是
min
{
s
+
k
m
∣
(
s
+
k
m
)
≡
x
(
m
o
d
n
)
}
\min\{s+km|(s+km)\equiv x(\mod n)\}
min{s+km∣(s+km)≡x(modn)},并且容易达到下界。
那么我们显然可以对于每个模
gcd
(
n
,
m
)
\gcd(n,m)
gcd(n,m)的等价类分开考虑。对于某个等价类,如果一开始没有开心的人那么显然无解,否则我们可以取其中的一个元素,将其他元素重新标号,使得相邻两个元素
m
o
d
n
\bmod \ n
mod n意义下公差为
m
m
m,这样得到了一个环,于是我们发现实质上是一开始环的某些位置有一些点,这些点每过
m
m
m个单位时间会向后扩散一个单位,问最少多少时间覆盖整个环。
这个问题显然可以二分+排序实现,时间复杂度
O
(
(
b
+
g
)
log
2
n
)
\mathcal O((b+g)\log^2n)
O((b+g)log2n)。可以做到更优复杂度但没必要。
#include <bits/stdc++.h>
#define FR first
#define SE second
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
void exgcd(ll a,ll b,ll &x,ll &y) {
if (!b) {
x=1;y=0;
}
else {
exgcd(b,a%b,y,x);
y-=(a/b)*x;
}
}
int getinv(int x,int y) {
ll t1,t2;
exgcd(x,y,t1,t2);
return (t1%y+y)%y;
}
vector <int> vt1[200005],vt2[200005];
int cur1[100005],cur2[100005];
pr q[500005];
bool check(int x,int n,int M,ll d) {
int cnt=0;
for(int i=0;i<vt1[x].size();i++) {
int u=cur1[i];
if (vt1[x][i]<=d) {
ll len=(d-vt1[x][i])/M+1;
if (len>=n) return 1;
if (u+len-1<n) q[++cnt]=pr(u,u+len-1);
else {
q[++cnt]=pr(u,n-1);
q[++cnt]=pr(0,(u+len-1)%n);
}
}
else q[++cnt]=pr(u,u);
}
for(int i=0;i<vt2[x].size();i++) {
int u=cur2[i];
if (vt2[x][i]<=d) {
ll len=(d-vt2[x][i])/M+1;
if (len>=n) return 1;
if (u+len-1<n) q[++cnt]=pr(u,u+len-1);
else {
q[++cnt]=pr(u,n-1);
q[++cnt]=pr(0,(u+len-1)%n);
}
}
}
sort(q+1,q+cnt+1);
int rx=-1;
for(int i=1;i<=cnt;i++) {
int l=q[i].FR,r=q[i].SE;
if (l>rx+1) return 0;
rx=max(rx,r);
}
return rx==n-1;
}
ll solve(int x,int n,int m,int d) {
if (!vt1[x].size()&&!vt2[x].size()) {
puts("-1");
exit(0);
}
ll inv=getinv(m,n);
for(int i=0;i<vt1[x].size();i++) cur1[i]=(vt1[x][i]-x)/d*inv%n;
for(int i=0;i<vt2[x].size();i++) cur2[i]=(vt2[x][i]-x)/d*inv%n;
ll l=0,r=1e18;
while (l<r) {
ll mid=((l+r)>>1);
if (check(x,n,m*d,mid)) r=mid; else l=mid+1;
}
return l;
}
int a[100005],b[100005];
int main() {
int n,m;
scanf("%d%d",&n,&m);
int d=__gcd(n,m);
n/=d;m/=d;
int B;
scanf("%d",&B);
for(int i=1;i<=B;i++) scanf("%d",&a[i]);
int G;
scanf("%d",&G);
for(int i=1;i<=G;i++) scanf("%d",&b[i]);
if (B+G<d) {
puts("-1");
return 0;
}
ll ans=0;
for(int i=0;i<d;i++) {
vt1[i].clear();
vt2[i].clear();
}
for(int i=1;i<=B;i++) vt1[a[i]%d].push_back(a[i]);
for(int i=1;i<=G;i++) vt2[b[i]%d].push_back(b[i]);
for(int i=0;i<d;i++)
ans=max(ans,solve(i,n,m,d));
for(int i=0;i<d;i++) {
vt1[i].clear();
vt2[i].clear();
}
for(int i=1;i<=B;i++) vt2[a[i]%d].push_back(a[i]);
for(int i=1;i<=G;i++) vt1[b[i]%d].push_back(b[i]);
for(int i=0;i<d;i++)
ans=max(ans,solve(i,m,n,d));
printf("%lld\n",ans);
return 0;
}