传送门
吐槽:
从各种意义上都难以形容的一道题。
好想到是好想,写起来真的。。。一言难尽。。。
(社论) 题解:
显然考虑分质因数来处理。
我们考虑每个数中当前处理的质因子的次数。
显然 g c d gcd gcd和 l c m lcm lcm此时就变成了一堆关于 min , max \min,\max min,max的限制。
对于每个数,显然次数不会超过 30 30 30,我们拆点来表示 x i x_i xi的次数,但是如果一个点 ( i , j ) (i,j) (i,j)表示 x i x_i xi中含有 j j j个 p p p的话,这显然就不是 2 − S A T 2-SAT 2−SAT。
考虑拆成两类点,其中 i d 1 [ i ] [ j ] id1[i][j] id1[i][j]表示 x i x_i xi中 p p p的次数 ≤ j \leq j ≤j, i d 2 [ i ] [ j ] id2[i][j] id2[i][j]表示 p p p的次数 > j > j >j。
显然是 2 − S A T 2-SAT 2−SAT。
按照 g c d gcd gcd和 l c m lcm lcm的意义连边就行了。
对了,在 2 − S A T 2-SAT 2−SAT中,如果需要强制选择 a a a,只需要从 a a a的反命题向 a a a连一条边就行了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
inline char get_char(){
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline char peek(){
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1;
}
inline char get_sth(){
while(isspace(peek()))gc();
return gc();
}
template<typename T>
inline T get(){
char c;
while(!isdigit(c=gc()));T num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int getint(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
namespace Graph{
cs int N=2e4+4;
int n;
std::vector<int> G[N];
inline void addedge(int u,int v){
G[u].push_back(v);
}
int scc[N],scc_cnt;
int low[N],dfn[N],clk;
int st[N],top;
bool inst[N];
void tarjan(int u){
low[u]=dfn[u]=++clk;
st[++top]=u;inst[u]=true;
for(int re v:G[u]){
if(!dfn[v]){
tarjan(v);
low[u]=std::min(low[u],low[v]);
}
else if(inst[v])low[u]=std::min(low[u],dfn[v]);
}
if(low[u]==dfn[u]){
++scc_cnt;
do{
scc[u]=scc_cnt;
u=st[top--];
inst[u]=false;
}while(low[u]!=dfn[u]);
}
}
inline void init(int _n){
n=_n;
for(int re i=1;i<=n;++i)G[i].clear();
memset(scc+1,0,sizeof(int)*n);
memset(low+1,0,sizeof(int)*n);
memset(dfn+1,0,sizeof(int)*n);
clk=top=scc_cnt=0;
}
inline void work(){
for(int re i=1;i<=n;++i)if(!dfn[i])tarjan(i);
}
inline bool iscon(int u,int v){return scc[u]==scc[v];}
}
namespace Solve{
cs int P=1e5+5;
std::vector<int> prime;
bool mark[P];
inline void linear_sieves(){
for(int re i=2;i<P;++i){
if(!mark[i])prime.push_back(i);
for(int re j:prime){
if(i*j>=P)break;
mark[i*j]=true;
if(i%j==0)break;
}
}
}
struct node{
int u,v,val,typ;
node(int _u,int _v,int _val,int _typ):u(_u),v(_v),val(_val),typ(_typ){}
};
cs int N=202,M=202;
int n,m,cnt;
int id1[N][35],id2[N][35];
//id1[i][j] a_i 的p的指数 <=j
//id2[i][j] a_i 的p的指数 > j
std::vector<node> vec;
std::unordered_map<int,int> id;
int p_cnt,factor[P];
inline void clear(){
vec.clear();
id.clear();p_cnt=0;
}
inline void work(int val){
for(int re i:prime){
if((ll)i*i>=val)break;
if(val%i==0){
while(val%i==0)val/=i;
if(id.find(i)==id.end()){
id[i]=++p_cnt;
factor[p_cnt]=i;
}
}
}
if(val>1){
if(id.find(val)==id.end()){
id[val]=++p_cnt;
factor[p_cnt]=val;
}
}
}
int mn[N],mx[N];
inline bool check(cs std::vector<node> &lim){
int Mx=0;cnt=0;
for(cs node &t:lim)Mx=std::max(Mx,t.val);
for(int re u=1;u<=n;++u){
mn[u]=0,mx[u]=Mx;
for(int re j=0;j<=Mx;++j){
id1[u][j]=++cnt;
id2[u][j]=++cnt;
}
}
Graph::init(cnt);using Graph::addedge;
for(int re u=1;u<=n;++u){
for(int re t=0;t<Mx;++t){
addedge(id1[u][t],id1[u][t+1]);
addedge(id2[u][t+1],id2[u][t]);
}
}
for(cs node &t:lim){
switch(t.typ){
case 1:{//gcd
int u=t.u,v=t.v,j=t.val;
mn[u]=std::max(mn[u],t.val);
mn[v]=std::max(mn[v],t.val);
addedge(id2[u][j],id1[v][j]);
addedge(id2[v][j],id1[u][j]);
break;
}
case 0:{//lcm
int u=t.u,v=t.v,j=t.val;
mx[u]=std::min(mx[u],t.val);
mx[v]=std::min(mx[v],t.val);
if(j){
addedge(id1[u][j-1],id2[v][j-1]);
addedge(id1[v][j-1],id2[u][j-1]);
}
break;
}
default:assert(0);
}
}
for(int re u=1;u<=n;++u){
if(mn[u]>mx[u])return false;
if(mn[u])addedge(id1[u][mn[u]-1],id2[u][mn[u]-1]);
addedge(id2[u][mx[u]],id1[u][mx[u]]);
}
Graph::work();
for(int re i=1;i<=n;++i){
for(int re j=0;j<=Mx;++j)if(Graph::iscon(id1[i][j],id2[i][j]))return false;
}
return true;
}
inline void main(){
n=getint(),m=getint();
while(m--){
char c=get_sth();
int u=getint()+1,v=getint()+1,val=getint();
work(val);
vec.push_back(node(u,v,val,c=='G'?1:0));
}
for(int re i=1;i<=p_cnt;++i){
std::vector<node> lim=vec;
int p=factor[i];
for(node &t:lim){
int power=0;
while(t.val%p==0)t.val/=p,++power;
t.val=power;
}
if(!check(lim)){
puts("Solution does not exist");
return ;
}
}
puts("Solution exists");
}
}
signed main(){
// freopen("formula.in","r",stdin);freopen("formula.out","w",stdout);
int T=getint();Solve::linear_sieves();
while(T--)Solve::clear(),Solve::main();
return 0;
}