题意
有n个男孩,m个女孩。都分别从0开始标号。
初始分别有b个男孩和g个女孩是高兴的。第
天时,男孩
和女孩
会碰面并传递高兴状态。(也就是说,只要有一个人是高兴的,那么过完这天两个人都变得高兴)。
现在问,多少天之后所有人都变得高兴,或判断无解。
思路
- 若 ,所有男孩与所有女孩都会碰面。此时是有解的。
- 否则,根据一些exgcd的常识,不难发现只要根据模gcd的余数分类,不同类之间是没有影响的,并且每一类中依然是上述情况。
- 因此,只要每一类中有至少一个高兴的人,就是有解的。问题变成了求每一类的最大答案。
- 不妨先考虑女孩这边。此时另一边的作用就是传递高兴和给初始的高兴状态:
- 若时刻T时女孩y是高兴的,则时刻T+n时,女孩 会变得高兴。
- 若男孩x初始是高兴的,那么时刻T女孩
会变得高兴。
初始高兴的男孩对其他女孩的贡献相当于利用他传递高兴,因此不需要考虑。
- 这看起来就很图论了,建个有向图,连上对应的边跑最短路即可。
- 虽然点数很多,但是这个图有很多度数为2的点(因为1类边实际上连出了一个环)。又由于所有边都是非负边,并且我们只需要最大的最短路。因此环上的一些无用点可以缩去。
- 两两关键点之间的环长使用exgcd求得即可。
对男孩也做上述过程,这题就搞定了。
(写的很丑…跑的很慢…)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int b, g, e, S;
ll n, m, len[N];
vector<ll> ori[N][2];
ll gcd(ll a, ll b) {
return b == 0 ? a : gcd(b, a % b);
}
map<int,int> idx,idy;
int node_cnt;
ll exgcd(ll a, ll b, ll &x0, ll &y0) {
if (b == 0) {
x0 = 1, y0 = 0;
return a;
}
ll x = 0, y = 0;
ll z = exgcd(b, a % b, x, y);
x0 = y;
y0 = x - a / b * y;
return z;
}
ll getdis(ll _a, ll _b, ll sz, ll len) { //x->(x+len)%sz
//k1 * len + k2 * sz = b - a
ll x = 0, y = 0, a = len, b = sz, c = _b - _a;
ll g = exgcd(a, b, x, y);
x = x * (c / g), y = y * (c / g);
//调整成最小非负整数解
ll o = b / g;
x %= o;
if (x < 0) x += o;
// cerr << _a << " " << _b << " " << x * len << endl;
return x * len;
}
vector<pair<int,ll>> edge[N * 8];
void link(int x, int y, ll len) {
edge[x].push_back(make_pair(y, len));
}
ll dis[N * 8];
void dij() {
memset(dis, 127, (node_cnt + 10) * 8);
dis[S] = 0;
static priority_queue<pair<ll,int>> pq;
pq.push(make_pair(0, S));
while(pq.size()) {
int x = pq.top().second;
ll le = pq.top().first;
pq.pop();
if (dis[x] != le) continue;
for(pair<int,ll> e : edge[x]) {
int y = e.first;
if (dis[x] + e.second < dis[y]){
dis[y] = dis[x] + e.second;
pq.push(make_pair(dis[y], y));
}
}
}
}
int cs[N * 8];
ll getans(ll w) {
node_cnt = 0;
static vector<ll> impx, impy;
impx = ori[w][0];
impy = ori[w][1];
for(int x : ori[w][0]) impy.push_back(x % m);
for(int y : ori[w][1]) impx.push_back(y % n);
for(int i = 0, ed = impx.size(); i < ed; i++) {
impx.push_back(((impx[i] - m) % n + n) % n);
}
for(int i = 0, ed = impy.size(); i < ed; i++) {
impy.push_back(((impy[i] - n) % m + m) % m);
}
sort(impx.begin(), impx.end());
sort(impy.begin(), impy.end());
impx.resize(unique(impx.begin(), impx.end()) - impx.begin());
impy.resize(unique(impy.begin(), impy.end()) - impy.begin());
//. Get all important points.
S = ++node_cnt;
idx.clear(), idy.clear();
for(int x : impx) idx[x] = ++node_cnt;
for(int y : impy) idy[y] = ++node_cnt;
memset(cs, 0, 4 * (node_cnt + 5));
//. number them.
for(int i = 1; i <= node_cnt; i++) edge[i].clear();
for(int x : ori[w][0]) {
cs[idx[x]] = 1;
link(S, idx[x], x), link(idx[x], idy[x % m], 0);
}
for(int y : ori[w][1]) {
cs[idy[y]] = 1;
link(S, idy[y], y), link(idy[y], idx[y % n], 0);
}
static vector<pair<ll,int>> cir; cir.clear();
for(int x : impx) {
cir.push_back(make_pair(getdis(impx.front(), x, n, m), x));
}
sort(cir.begin(), cir.end());
pair<ll,int> las = make_pair(-1, -1);
for(pair<ll,int> x : cir) {
if (las.first != -1) {
link(idx[las.second], idx[x.second], x.first - las.first);
}
las = x;
}
if (las.first!=-1)
link(idx[las.second], idx[cir.front().second], getdis(las.second, cir.front().second, n, m));
cir.clear();
for(int y : impy) {
cir.push_back(make_pair(getdis(impy.front(), y, m, n), y));
}
sort(cir.begin(), cir.end());
las = make_pair(-1, -1);
for(pair<ll,int> y : cir) {
// cerr << y.second << " ";
if (las.first != -1) {
link(idy[las.second], idy[y.second], y.first - las.first);
}
las = y;
}
if (las.first!=-1)
link(idy[las.second], idy[cir.front().second], getdis(las.second, cir.front().second, m, n));
dij();
ll ret = 0;
for(int i = 1; i <= node_cnt; i++) if(!cs[i])
ret = max(ret, dis[i]);
return ret;
}
int main() {
freopen("e.in","r",stdin);
cin >> n >> m;
e = gcd(n, m);
if (e > 2e5) {
printf("-1"); return 0;
}
cin >> b;
for(int i = 1; i <= b; i++) {
int t; scanf("%d", &t);
ori[t % e][0].push_back(t);
}
cin >> g;
for(int i = 1; i <= g; i++) {
int t; scanf("%d", &t);
ori[t % e][1].push_back(t);
}
for(int i = 0; i < e; i++) {
if (ori[i][0].size() + ori[i][1].size() == 0) {
printf("-1\n"); return 0;
}
}
ll ans = 0;
for(int i = 0; i < e; i++) {
ans = max(ans, getans(i));
}
cout << ans << endl;
}