zoukankan      html  css  js  c++  java
  • 洛谷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;
    }
    
  • 相关阅读:
    diary and html 文本颜色编辑,行距和其它编辑总汇
    bash coding to changeNames
    virtualbox ubuntu 网络连接 以及 连接 secureCRT
    linux 学习6 软件包安装
    linux 学习8 权限管理
    vim 使用2 转载 为了打开方便
    ubuntu
    linux 学习15 16 启动管理,备份和恢复
    linux 学习 14 日志管理
    linux 学习 13 系统管理
  • 原文地址:https://www.cnblogs.com/KnightL/p/14874485.html
Copyright © 2011-2022 走看看