卧薪尝胆,厚积薄发。
最大公约数与最小公倍数方程组
Date: Mon Aug 27 15:52:17 CST 2018
In Category:
NoCategory
Description:
有
$n$
个未知数,
$m$
个方程组,方程组有两种:
$gcd(x_i,x_j)=k$
或
$lcm(x_i,x_j)=k$
,判断方程组是否有解。
$1\le n,m\le 200$
Solution:
$gcd$
和
$lcm$
可以通过指数取
$max/min$
来计算,可以把每个数拆成所有素因子,每个素因子再拆成所有指数,即变量
$s[i][j][k]$
表示
$p_j^k$
是否整除
$x_i$
,那么
$s[i][j][1]$
即代表
$x_i$
是否含有
$p_j$
这个素因子,通过这种方法可以把问题转化成一个
$2-SAT$
问题,显然必须连边
$s[i][j][k]\to s[i][j][k-1]$
,
$\lnot s[i][j][k-1]\to \lnot s[i][j][k]$
分类讨论:
$1$
、
$gcd$
对于没有出现在
$gcd$
中的每个素数
$p_k$
,他们要么没有出现,要么只出现在了
$x_i$
或
$x_j$
中,于是连边
$s[i][k][1]\to\lnot s[j][k][1]$
,
$s[j][k][1]\to\lnot s[i][k][1]$
。
对于出现过的素数
$p_k$
,设他的指数为
$w$
,首先必须要强制
$s[i][k][w]$
和
$s[j][k][w]$
为真,他的对应变量为假,只要把假向真连一条边即可,因为这样如果假那么真,所以假一定不合法,所以一定真,然后他的更高次幂一定只在一个数中出现,于是连边
$s[i][k][w+1]\to \lnot s[j][k][w+1]$
,
$s[j][k][w+1]\to\lnot s[i][k][w+1]$
。
$2$
、
$lcm$
对于没有出现在
$lcm$
中的每个素数
$p_k$
,他们一定没有出现,于是强制
$s[i][k][1]$
和
$s[j][k][1]$
为假,只要把真向假连一条边即可。
对于出现了的素数
$p_k$
,设他的指数为
$w$
,强制
$s[i][k][w+1]$
和
$s[j][k][w+1]$
为假,还要保证一定至少有一个
$w$
为真,于是
$\lnot s[i][k][w]\to s[j][k][w]$
,
$\lnot s[j][k][w]\to s[i][k][w]$
。
然后只要判断
$s[i][j][k]$
和
$\lnot s[i][j][k]$
不在同一强连通分量里即可。
切记每一个
$testcases$
要把该清零的清零。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
#include<set>
#include<stack>
#include<cctype>
#include<cstring>
using namespace std;
int n,m;
#define MAXN 210
char getc()
{
char c = getchar();
while(c != 'L' && c != 'G')c = getchar();
return c;
}
inline int read()
{
register int res = 0;
register char c = getchar();
while(!isdigit(c))c = getchar();
while(isdigit(c))
{
res = (res << 1) + (res << 3) + c - '0';
c = getchar();
}
return res;
}
#define MAX 1000000000
map<int,map<int,map<int,map<int,int> > > > s;
int ptr = 0;
#define MAXD 1000000
#define MAXE 10000000
struct edge
{
int to,nxt;
}e[MAXE];
int edgenum = 0;
int lin[MAXD];
void add(int a,int b)
{
++edgenum;e[edgenum].to = b;e[edgenum].nxt = lin[a];lin[a] = edgenum;
return;
}
int dfn[MAXD],low[MAXD],cnt = 0;
int ins[MAXD],scc = 0;
bool v[MAXD];
stack<int> st;
void tarjan(int k)
{
dfn[k] = low[k] = ++cnt;
v[k] = true;st.push(k);
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(dfn[e[i].to] == 0)
{
tarjan(e[i].to);
low[k] = min(low[k],low[e[i].to]);
}
else if(v[e[i].to])
{
low[k] = min(low[k],dfn[e[i].to]);
}
}
if(dfn[k] == low[k])
{
++scc;
int t;
do
{
t = st.top();st.pop();
ins[t] = scc;v[t] = false;
}while(t != k);
}
return;
}
char c[MAXN];
int a[MAXN],b[MAXN],t[MAXN];
set<int> prime;
map<int,int> p;
map<int,int> times;
int tot = 0;
void work()
{
memset(lin,0,sizeof(lin));
edgenum = 0;
prime.clear();p.clear();tot = 0;s.clear();
scanf("%d%d",&n,&m);
int w;
for(int i = 1;i <= m;++i)
{
c[i] = getc();a[i] = read();b[i] = read();t[i] = read();++a[i];++b[i];
w = t[i];
for(int j = 2;j * j <= t[i];++j)
{
if(w % j == 0)
{
if(prime.find(j) == prime.end())
prime.insert(j);
while(w % j == 0)w /= j;
}
}
if(w != 1)
if(prime.find(w) == prime.end())
prime.insert(w);
}
for(set<int>::iterator it = prime.begin();it != prime.end();++it)
{
p[++tot] = *it;
times[tot] = log2(MAX) / log2(*it);
}
ptr = 0;
for(int i = 1;i <= n;++i)
for(int j = 1;j <= tot;++j)
for(int k = 1;k <= times[j];++k)
s[i][j][k][1] = ++ptr,s[i][j][k][0] = ++ptr;
for(int i = 1;i <= n;++i)
for(int j = 1;j <= tot;++j)
for(int k = 2;k <= times[j];++k)
add(s[i][j][k][1],s[i][j][k - 1][1]);
for(int i = 1;i <= n;++i)
for(int j = 1;j <= tot;++j)
for(int k = 2;k <= times[j];++k)
add(s[i][j][k - 1][0],s[i][j][k][0]);
for(int i = 1;i <= m;++i)
{
if(c[i] == 'G')
{
for(int k = 1;k <= tot;++k)
{
if(t[i] % p[k] == 0)
{
int cnt = 0;
int y = t[i];while(y % p[k] == 0){++cnt;y /= p[k];}
add(s[a[i]][k][cnt][0],s[a[i]][k][cnt][1]);
add(s[b[i]][k][cnt][0],s[b[i]][k][cnt][1]);
add(s[a[i]][k][cnt + 1][1],s[b[i]][k][cnt + 1][0]);
add(s[b[i]][k][cnt + 1][1],s[a[i]][k][cnt + 1][0]);
}
else
{
add(s[a[i]][k][1][1],s[b[i]][k][1][0]);
add(s[b[i]][k][1][1],s[a[i]][k][1][0]);
}
}
}
else
{
for(int k = 1;k <= tot;++k)
{
if(t[i] % p[k] == 0)
{
int cnt = 0;
int y = t[i];while(y % p[k] == 0){++cnt;y /= p[k];}
add(s[a[i]][k][cnt][0],s[b[i]][k][cnt][1]);
add(s[b[i]][k][cnt][0],s[a[i]][k][cnt][1]);
add(s[a[i]][k][cnt + 1][1],s[a[i]][k][cnt + 1][0]);
add(s[b[i]][k][cnt + 1][1],s[b[i]][k][cnt + 1][0]);
}
else
{
add(s[a[i]][k][1][1],s[a[i]][k][1][0]);
add(s[b[i]][k][1][1],s[b[i]][k][1][0]);
}
}
}
}
memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));cnt = 0;scc = 0;
for(int i = 1;i <= ptr;++i)if(dfn[i] == 0)tarjan(i);
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= tot;++j)
{
for(int k = 1;k <= times[j];++k)
{
if(ins[s[i][j][k][1]] == ins[s[i][j][k][0]])
{
puts("Solution does not exist");
return;
}
}
}
}
puts("Solution exists");
return;
}
int main()
{
int testcases = 0;
scanf("%d",&testcases);
while(testcases--)work();
return 0;
}
In tag:
图论-连通性-2-SAT
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡