bzoj 4602: [Sdoi2016]齿轮
题解:
一个简单的dfs或并查集即可搞定。
dfs做法:建出图来以后,由一个节点跑一遍,如果儿子节点没有被遍历过,dfs此节点,否则,判断他俩的比例与他俩到根节点的比例之比是否相等。
对于判断两节点的比例,double可以安全存下。
我怕炸精度(其实不会,感觉自己跟个zz一样),于是想不用double,用个pair存下分子分母。后来觉得导起来太麻烦,于是用逆元求(越来越傻了)。
逆元不需要太大的素数,大了会T,小了会WA。
bzoj上测试了6个素数:1000000007,66191,7307,233,151,103.测试结果如下。
附上代码:
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstring> 4 #include<cstdio> 5 #include<algorithm> 6 #include<cmath> 7 using namespace std; 8 #define ll long long 9 struct tree{ 10 int u,v,next; 11 ll d; 12 }l[20100]; 13 ll mod=151,dis[1010]; 14 int lian[20100],n,m,t,e; 15 bool pd[1010],cuo; 16 ll ksm(ll,ll); 17 void bian(int,int,ll); 18 void dfs(int,int); 19 int main() 20 { 21 // freopen("in.txt","r",stdin); 22 scanf("%d",&t); 23 for(int jjj=1;jjj<=t;jjj++) 24 { 25 memset(dis,0,sizeof(dis)); 26 memset(lian,0,sizeof(lian)); 27 memset(pd,0,sizeof(pd)); 28 e=0;cuo=0; 29 scanf("%d%d",&n,&m); 30 for(int i=1;i<=m;i++) 31 { 32 int x,y,u,v; 33 scanf("%d%d%d%d",&x,&y,&u,&v); 34 bian(x,y,(ll)v*ksm(u,mod-2)%mod); 35 bian(y,x,(ll)u*ksm(v,mod-2)%mod); 36 } 37 for(int i=1;i<=n;i++) 38 { 39 if(pd[i]==0) 40 { 41 dis[i]=1; 42 dfs(i,i); 43 if(cuo==1) break; 44 } 45 } 46 printf("Case #%d: ",jjj); 47 if(cuo==0) printf("Yes\n"); 48 else printf("No\n"); 49 } 50 return 0; 51 } 52 ll ksm(ll x,ll y) 53 { 54 ll z=x,sum=1; 55 while(y) 56 { 57 if(y&1) 58 sum=sum*z%mod; 59 y>>=1; 60 z=z*z%mod; 61 } 62 return sum; 63 } 64 void bian(int x,int y,ll z) 65 { 66 e++; 67 l[e].u=x; 68 l[e].v=y; 69 l[e].d=z; 70 l[e].next=lian[x]; 71 lian[x]=e; 72 } 73 void dfs(int x,int fa) 74 { 75 for(int i=lian[x];i;i=l[i].next) 76 { 77 int v=l[i].v; 78 if(v==fa) continue; 79 if(pd[v]==0) 80 { 81 dis[v]=dis[x]*l[i].d%mod; 82 pd[v]=1; 83 dfs(v,x); 84 } 85 else 86 { 87 ll d=ksm(dis[x],mod-2)*dis[v]%mod; 88 if(d!=l[i].d) cuo=1; 89 } 90 } 91 }