NOI模拟 序列

涉及知识点:数论,图论转化建图

题意

有一串长为 \(n\ (\leq10^3)\) 序列 \(a\),给出 \(m\ (\leq10^3)\) 个条件,每条条件形如 \(\gcd(a_i,a_j)=k\),问是否存在这样的序列满足所有条件。保证不存在重复的 \((a_i,a_j)\) 对。

思路

把题目给出的所有关系建成图,点 \(i\) 代表 \(a_i\)\(\gcd(a_i,a_j)=k\) 转化为 \(i\)\(j\) 边权为 \(k\) 的边。将每个节点的点权设为与它相连的所有边边权的最小公倍数,可以证明,假如条件合法,这将是最小的合法值。

然后再遍历每条边,记为 \((u,v,k)\),判断 \(u\)\(v\) 点权的 \(\gcd\) 是否为 \(k\),可以发现:

  • 如果 \(k<\gcd\),因为 \(u\)\(v\) 的点权已经是最小,无法再变小,因此它们的 \(\gcd\) 也不可能再变小,该情况不合法。
  • 如果 \(k=\gcd\),该情况符合题意,合法。
  • 如果 \(k>\gcd\),不存在这种情况,因为 \(u\)\(v\) 的点权都为 \(k\) 的倍数,它们的 \(\gcd\) 无论如何都不可能小于 \(k\)

因此,判断每条边即可。

代码

代码似乎会爆精度,莫名其妙就过了,有bug慎阅

#include<bits/stdc++.h>
using namespace std;
#ifdef ONLINE_JUDGE
#define getchar __getchar
inline char __getchar(){
    static char ch[1<<20],*l,*r;
    return (l==r&&(r=(l=ch)+fread(ch,1,1<<20,stdin),l==r))?EOF:*l++;
}
#endif
template<class T>inline void rd(T &x){
    T res=0,f=1;
    char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while('0'<=ch && ch<='9'){res=res*10+ch-'0';ch=getchar();}
    x=res*f;
}
template<class T>inline void wt(T x,char endch='\0'){
    static char wtbuff[20];
    static int wtptr;
    if(x==0){
        putchar('0');
    }
    else{
        if(x<0){x=-x;putchar('-');}
        wtptr=0;
        while(x){wtbuff[wtptr++]=x%10+'0';x/=10;}
        while(wtptr--) putchar(wtbuff[wtptr]);
    }
    if(endch!='\0') putchar(endch);
}
typedef long long LL;
typedef __int128_t int128;
const int MAXN=1e3+5;
int n,m,head[MAXN],ecnt=1;
int128 val[MAXN];
struct EDGE{
    int v,nxt;
    int128 w;
}e[MAXN<<2];
inline void add(const int& u,const int& v,const int128& w){
    e[++ecnt].v=v;
    e[ecnt].w=w;
    e[ecnt].nxt=head[u];
    head[u]=ecnt;
}
inline int128 __lcm(int128 x,int128 y){
    return x*y/__gcd(x,y);
}
inline void solve(){
    memset(head,0,sizeof(head));
    ecnt=1;
    
    rd(n);rd(m);
    for(int i=1,u,v;i<=m;i++){
        int128 w;
        rd(u);rd(v);rd(w);
        add(u,v,w);add(v,u,w);
    }

    for(int i=1;i<=n;i++){
        val[i]=1;
        for(int j=head[i];j;j=e[j].nxt){
            val[i]=__lcm(val[i],e[j].w);
        }
    }

    for(int i=2;i<=ecnt;i+=2){
        if(__gcd(val[e[i].v],val[e[i^1].v])!=e[i].w){
            puts("No");
            return;
        }
    }
    puts("Yes");
}
int main(){
    int t;
    rd(t);
    while(t--) solve();
    return 0;
}
posted @ 2024-05-09 23:27  MessageBoxA  阅读(12)  评论(0编辑  收藏  举报