bzoj4602: [Sdoi2016]齿轮

题外话

  浏览器坏掉了…昨天一下午没发题解,现在只好一块发出去。

简述

  来做一下传说中的送分题。。。我可能比较智障所以调了好长时间,想是很好想
  首先考虑 double 暴力,这个没啥好说的,暴力 dfs ,竟然有人用 double 水过去了!
  把 1 100的素数乘起来发现已经爆了 long long ,所以不可能求出 lcm 然后乱搞,那怎么办??
  看下数据规模,发现 T×M 竟然才 105 ?也就是说我们还有再加两个 0 的余地,嗯…立马就想到每个数用素数的幂表示。
  然后就AC了。

代码

//分解质因数+dfs
#include <cstdio>
#include <algorithm>
#define maxn 100000
#define abs(x) (x>0?x:-x)
using namespace std;
int N, M, T, head[maxn], nex[maxn], to[maxn], w1[maxn], w2[maxn], tot, prime[100],
    vis[maxn];
struct num
{
    int q[100], fu;
    void clear(){for(int i=1;i<=*prime;i++)q[i]=0;}
}w[maxn], nb[123], big;
int gcd(int a, int b){return !b?a:gcd(b,a%b);}
num operator*(num a, int b)
{
    int i;
    num c;
    c.clear();
    for(i=1;i<=*prime;i++)c.q[i]=a.q[i]+nb[abs(b)].q[i];
    c.fu=a.fu^(b<0);
    return c;
}
num operator/(num a, int b)
{
    int i;
    num c;
    c.clear();
    for(i=1;i<=*prime;i++)c.q[i]=a.q[i]-nb[abs(b)].q[i];
    c.fu=a.fu^(b<0);
    return c;
}
bool cmp(num a, num b)
{
    int i;
    if(a.fu!=b.fu)return false;
    for(i=1;i<=*prime;i++)if(a.q[i]!=b.q[i])return false;
    return true;
}
void adde(int a, int b, int v1, int v2)
{
    to[++tot]=b;nex[tot]=head[a];head[a]=tot;
    w1[tot]=v1, w2[tot]=v2;
}
void init()
{
    int i, j, t;
    for(i=2;i<=100;i++)
    {
        for(j=2;j*j<=i;j++)if(i%j==0)break;
        if(j*j>i)prime[++*prime]=i;
    }
    for(i=2;i<=100;i++)
        for(j=1;j<=*prime;j++)
            for(t=i;t%prime[j]==0;nb[i].q[j]++,t/=prime[j]);
    for(i=1;i<=100;i++)big.q[i]=100;
}
void build()
{
    int i, j, u, v, x, y;
    scanf("%d%d",&N,&M);
    for(i=1;i<=tot;i++)nex[i]=0;
    for(i=1;i<=N;i++)head[i]=0;
    tot=0;
    for(i=1;i<=M;i++)scanf("%d%d%d%d",&u,&v,&x,&y), adde(u,v,x,y), adde(v,u,y,x);
    for(i=1;i<=N;i++)vis[i]=0;
}
bool dfs(int pos)
{
    int p; num t;
    vis[pos]=1;
    for(p=head[pos];p;p=nex[p])
    {
        t=w[pos]/w1[p]*w2[p];
        if(vis[to[p]])
        {
            if(!cmp(w[to[p]],t))return false;
        }
        else
        {
            w[to[p]]=t;
            if(!dfs(to[p]))return false;
        }
    }
    return true;
}
int main()
{
    int T, i, j; bool f;
    init();
    scanf("%d",&T);
    for(i=1;i<=T;i++)
    {
        build();
        w[1]=big;
        f=dfs(1);
        for(j=1;j<=N;j++)if(!vis[j])f=f and dfs(j);
        printf("Case #%d: ",i);
        printf(f?"Yes\n":"No\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值