• 洛谷P5676


    Description

    给定一个点,初始权值 ( ext{val}=1),有两种操作:

    • 可以将 ( ext{val}) 变为自己的整数倍;

    • ( ext{val}=w_i) 时,可以将 ( ext{val}) 变为 (e_i) ((iin[1,n]))

    问有没有哪种操作可以重复进行。

    Solution

    既然是权值的变化关系,也就是说一种权值只有一个点。

    所以我们可以建一张图,以权值为点,以题目中给出的信息为条件建单向边,然后我们对这张图进行缩点。

    如果有某个 (w_i)(e_i) 在同一个 SCC 中,则证明他们互相可达或者相等,也就是说这个 (w_i o e_i) 的操作可以执行多遍。

    然后这个题目就可以解决了。

    当然我们还可以对其进行优化,对于每个点 (i),我们只连 ((i,i imes j),j in ext{prime}) 的边。

    因为对于 ((i,i imes j),j otin ext{prime}) 的边,我们即使不连,(i) 点也可以通过其他的几条边到达 (i imes j) 点。

    所以我们按其给的数据范围 (1le nle 100,000) 筛出这里的所有质数,然后连边求即可。实测跑得飞快。

    Code

    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define rr register 
    #define maxn 100010
    #define INF 0x3f3f3f3f
    //#define int long long
    
    using namespace std;
    
    bool vis[maxn],flag[maxn];
    int T,t,n,tot,top,cnt,all,ans;
    int W[maxn],E[maxn],head[maxn],Plist[maxn];
    int low[maxn],dfn[maxn],num[maxn],zhan[maxn];
    struct edge{int fr,to,nxt;}e[maxn*50];
    
    inline int read(){
      rr int s=0,w=1;char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
      while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
      return s*w;
    }
    
    inline void add(int fr,int to){
      e[++tot]=(edge){fr,to,head[fr]};head[fr]=tot;
    }
    
    inline void clear(){
      tot=cnt=ans=top=0;
      memset(dfn,0,sizeof dfn);
      memset(head,0,sizeof head);
    }
    
    void shai(){
      flag[0]=flag[1]=true;
      for(rr int i=2;i<=100000;i++){
        if(!flag[i])Plist[++all]=i;
        for(rr int j=1;j<=all&&i*Plist[j]<=100000;j++){
          int x=i*Plist[j];flag[x]=true;if(!(i%Plist[j]))break;
        }
      }  
    }
    
    void tarjan(int u){
      dfn[u]=low[u]=++cnt;
      zhan[++top]=u;vis[u]=1;
      for(rr int i=head[u];i;i=e[i].nxt){
        int to=e[i].to;
        if(!dfn[to])tarjan(to),low[u]=min(low[u],low[to]);
        else if(vis[to]) low[u]=min(low[u],dfn[to]);
      }
      if(dfn[u]==low[u]){
        int pre=zhan[top--];
        num[pre]=++t;vis[pre]=0;
        while(pre!=u){
          pre=zhan[top--];
          num[pre]=t;vis[pre]=0;
        }
      }
    }
    
    int main(){
      shai();
      T=read();
      while(T--){
        n=read();clear();
        for(rr int i=1;i<=n;i++)W[i]=read();
        for(rr int i=1;i<=n;i++)add(W[i],E[i]=read());
        for(rr int i=1;i<=100000;i++)
          for(rr int j=1;Plist[j]*i<=100000;j++)
            add(i,i*Plist[j]);
        tarjan(1);
        for(rr int i=1;i<=n;i++)ans+=(num[W[i]]==num[E[i]]);
        printf("%d
    ",ans);
      }
      return 0;
    }
    
  • 相关阅读:
    Java中的线程安全问题
    谈谈你对Spring的理解
    Word 2016问题导致无法创建其他博客账号
    JS中 Cookie、 LocalStorage 与 SessionStorage
    CSDN代码块显示颜色
    Java中创建线程的两种方式
    毕业设计每日博客——第五周1
    毕业设计每日博客--第四周5
    毕业设计每日博客--第四周4
    毕业设计每日博客--第四周3
  • 原文地址:https://www.cnblogs.com/KnightL/p/14874485.html
Copyright © 2020-2023  润新知