题解:
首先分解质因数,gcd就相当于指数的min,lcm就相当于指数的max。
于是问题变成了这样:
给出一坨类似于以下的限制:
min(a,b) = c
max(a,b) = c
问是否有解?
以min为例.
min(a,b) = c
即(a >= c) and (b >= c) and (a = c or b = c)
注意到指数是很小的,c不超过三十。
于是可以把x拆成31(0->30)个组,每个点再拆2个, xi 表示x<=i的布尔值, x′i 就是x>i的布尔值,这两个刚好必须选一个。
xi
一定要向
xi+1
连边,
x′i
也一定要向
x′i−1
连边。
a>=c,所以
ai
->
a′c−1(0<=i<c)
b>=c,同理。
a = c or b = c,因为已经有了a>=c and b >= c,可以看成a <= c or b <= c,
所以
ai
->
bc(i>c)
,
bi
->
ac(i>c)
然后跑过Trjan判断一下有没有 xi 和 x′i 在一个强联通分量里即可。
Code:
#include<set>
#include<cstdio>
#include<algorithm>
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
const int N = 1e6;
bool bz[N + 5]; int p[N];
char S[N];
int T, n, m, a[N], b[N], c[N];
int u[50], v[50];
int next[N], to[N], final[N], tot;
int num[205][105][2], tt, mx;
void Shai() {
fo(i, 2, N) {
if(!bz[i]) p[++ p[0]] = i;
fo(j, 1, p[0]) {
int k = i * p[j];
if(k > N) break;
bz[k] = 1;
if(i % p[j] == 0) break;
}
}
}
void Fen(int x) {
u[0] = 0;
for(int i = 1; p[i] * p[i] <= x; i ++)
if(x % p[i] == 0) {
u[++ u[0]] = p[i], v[u[0]] = 0;
while(x % p[i] == 0)
x /= p[i], v[u[0]] ++;
}
if(x > 1) u[++ u[0]] = x, v[u[0]] = 1;
}
int Q_z(int x, int y) {
int z = 0; while(x % y == 0) x /= y, z ++;
return z;
}
set<int> s;
void Clear() {
fo(i, 1, tot) next[i] = 0;
fo(i, 1, tt) final[i] = 0;
tot = 0;
}
void link(int x, int y) {
next[++ tot] = final[x], to[tot] = y, final[x] = tot;
}
int z[N], dfn[N], low[N], ff[N], d[N], bd[N], td;
void dg(int x) {
bd[x] = 1; d[++ d[0]] = x;
dfn[x] = low[x] = ++ td;
for(int i = final[x]; i; i = next[i]) {
int y = to[i];
if(!dfn[y]) dg(y), low[x] = min(low[x], low[y]); else
if(bd[y]) low[x] = min(low[x], dfn[y]);
}
if(low[x] == dfn[x]) {
for(; d[d[0]] != x; d[0] --)
ff[d[d[0]]] = x, bd[d[d[0]]] = 0;
d[0] --; ff[x] = x; bd[x] = 0;
}
}
bool pd() {
td = 0;
fo(i, 1, tt) low[i] = 0, dfn[i] = 0;
fo(i, 1, tt) if(!dfn[i])
dg(i);
fo(i, 1, n) fo(j, 0, mx) {
if(ff[num[i][j][0]] == ff[num[i][j][1]]) {
return 0;
}
}
return 1;
}
char get() {
char c = ' '; for(;c != 'G' && c != 'L'; c = getchar());
return c;
}
int main() {
Shai();
for(scanf("%d", &T); T; T --) {
s.clear();
scanf("%d %d", &n, &m);
fo(i, 1, m) {
S[i] = get();
scanf("%d %d %d", &a[i], &b[i], &c[i]);
a[i] ++; b[i] ++;
Fen(c[i]);
fo(i, 1, u[0]) s.insert(u[i]);
}
int ans = 1;
while(!s.empty()) {
int x = *s.begin(); s.erase(x);
mx = 0;
fo(i, 1, m) z[i] = Q_z(c[i], x), mx = max(mx, z[i]);
tt = 0; fo(i, 1, n) fo(j, 0, mx) num[i][j][0] = ++ tt, num[i][j][1] = ++ tt;
fo(i, 1, n) fo(j, 0, mx - 1) link(num[i][j][0], num[i][j + 1][0]);
fo(i, 1, n) fo(j, 1, mx) link(num[i][j][1], num[i][j - 1][1]);
Clear();
fo(i, 1, m) {
if(S[i] == 'G') {
fo(j, 0, z[i] - 1) {
link(num[a[i]][j][0], num[a[i]][j][1]);
link(num[b[i]][j][0], num[b[i]][j][1]);
}
fo(j, z[i], mx) {
link(num[a[i]][j][1], num[b[i]][z[i]][0]);
link(num[b[i]][j][1], num[a[i]][z[i]][0]);
}
} else {
fo(j, z[i], mx) {
link(num[a[i]][j][1], num[a[i]][j][0]);
link(num[b[i]][j][1], num[b[i]][j][0]);
}
fo(j, 0, z[i] - 1) {
link(num[a[i]][j][0], num[b[i]][z[i] - 1][1]);
link(num[b[i]][j][0], num[a[i]][z[i] - 1][1]);
}
}
}
ans &= pd();
if(!ans) break;
}
if(ans) printf("Solution exists\n"); else printf("Solution does not exist\n");
}
}