bzoj4602 [Sdoi2016]齿轮

传送门
Description

现有一个传动系统,包含了N个组合齿轮和M个链条。每一个链条连接了两个组合齿轮u和v,并提供了一个传动比x:y。即如果只考虑这两个组合齿轮,编号为u的齿轮转动x圈,编号为v的齿轮会转动y圈。传动比为正表示若编号为u的齿轮顺时针转动,则编号为v的齿轮也顺时针转动。传动比为负表示若编号为u的齿轮顺时针转动,则编号为v的齿轮会逆时针转动。若不同链条的传动比不相容,则有些齿轮无法转动。我们希望知道,系统中的这N个组合齿轮能否同时转动。
Input

有多组数据,第一行给定整数T,表示总的数据组数,之后依次给出T组数据。每一组数据的第一行给定整数N和M,表示齿轮总数和链条总数。之后有M行,依次描述了每一个链条,其中每一行给定四个整数u,v,x和y,表示只考虑这一组联动关系的情况下,编号为u的齿轮转动x圈,编号为v的齿轮会转动y圈。请注意,x为正整数,而y为非零整数,但是y有可能为负数。
T<=32,N<=1000,M<=10000且x与y的绝对值均不超过100
Output

输出T行,对应每一组数据。首先应该输出标识这是第几组数据,参见样例输出。之后输出判定结果,如果N个组合齿轮可以同时正常运行,则输出Yes,否则输出No。
Sample Input
2
3 3
1 2 3 5
2 3 5 -7
1 3 3 -7
3 3
1 2 3 5
2 3 5 -7
1 3 3 7
Sample Output
Case #1: Yes
Case #2: No
HINT
Source
By AHdoc命题 鸣谢Loi_DQS上传

题解

奇怪的并查集,然而为什么跑的这么慢QAQ
也许是用了long long的缘故,然而并没有办法

CODE:

#include<cstdio>
typedef long long ll;
int f[1005];
ll rotate[1005][2];
bool same[1005];
int T,n,m,x,y;
ll u,v;
bool ans;
inline ll abs(ll n){if(n<0)return -n;return n;}
ll gcd(ll a,ll b)
{
    if(!b) return a;
    return gcd(b,a%b);
}
inline ll lcm(ll a,ll b)
{
    return a*b/gcd(a,b);
}
int find(int n)
{
    if(f[n]!=n)
    {
        int tmp=find(f[n]);
        if(same[n]==same[f[n]]) same[n]=1;
        else same[n]=0;
        ll T=lcm(rotate[n][1],rotate[f[n]][0]);
        rotate[n][0]*=T/rotate[n][1];
        rotate[n][1]=rotate[f[n]][1]*T/rotate[f[n]][0];
        T=gcd(rotate[n][0],rotate[n][1]);
        rotate[n][0]/=T,rotate[n][1]/=T;
        f[n]=tmp;
    }
    return f[n];
}
inline bool merge(int x,int y,ll u,ll v)
{
    int xx=find(x),yy=find(y);
    ll tmp=lcm(u,lcm(abs(v),lcm(rotate[x][0],lcm(rotate[x][1],lcm(rotate[y][0],rotate[y][1])))));
    u*=tmp,v*=tmp;
    u/=rotate[x][0],u*=rotate[x][1];
    v/=rotate[y][0],v*=rotate[y][1];
    tmp=gcd(u,abs(v));
    u/=tmp,v/=tmp;
    int t=1;
    if(!same[x]) t^=1;
    if(!same[y]) t^=1;
    if(v<0) t^=1,v=-v;
    if(xx!=yy)
    {
        if(!t) same[yy]=0;
        rotate[yy][0]=v,rotate[yy][1]=u;
        f[yy]=xx;
        return 1;
    }
    if(!t==same[yy]||rotate[yy][0]!=v||rotate[yy][1]!=u) return 0;
    return 1;
}
int main()
{
    scanf("%d",&T);
    for(int k=1;k<=T;k++)
    {
        scanf("%d%d",&n,&m);
        ans=1;
        for(int i=1;i<=n;i++)
          f[i]=i,rotate[i][0]=rotate[i][1]=same[i]=1;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%lld%lld",&x,&y,&u,&v);
            ll tmp=gcd(u,abs(v));
            u/=tmp,v/=tmp;
            if(ans&&!merge(x,y,u,v)) ans=0;
        }
        if(ans) printf("Case #%d: Yes\n",k);
        else printf("Case #%d: No\n",k);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值