ACM 赵信的往事

NOJ 2096
题目描述
赵信——德玛西亚的总管,可谓一人之下,万人之上。但谁能想到,他以前在诺克萨斯的角斗场过的是怎样的生活?
那时,成千上万的奴隶或战俘被抓进角斗场,通过血腥的杀戮供贵族们取乐。所以,为了活下去,除了自身的实力之外,拉帮结派也是必不可少的。显然,这样的事只可能发生在互相信赖的人的中间,而在当时,人们互相信赖的标准却很奇怪——每个人都有一个编号,若两个人可以相互信赖,那么当且仅当这两个编号的素因子集合相同。
那么问题来了:
现在有三个人想组团,请问他们能相互信赖么?
输入
先输入一个正整数T,表示共有T组测试样例,1≤T≤10000。
对于每一个测试样例,输入三个正整数,对于第i个数pi,表示第i个人的编号(1≤pi≤109)。
输出
对于每组样例,如果可以可以成功组团,则输出“YES”,否则输出“NO”。
样例输入
2
3 6 9
3 9 27
样例输出
NO
YES

这道题目拿到手,简单想想,如果真是要算出自然数x的素数集,肯定是TL了。所以,要判断自然数x与y的素数集相同,必须从最大公约数入手。很简单的,求最大公约数的函数int gcd(int, int)如下所示:

int gcd(int x,int y)
{
    int c;
    while(x%y!=0)
    {
        c=x%y;
        x=y;
        y=c;
    }
    return y;
}

判断两个素数集相等,应该是一件不容易的事情,可以如果要判断一个数的素数集包含另一个数的素数集(即后者的素数集是前者素数集的子集),那就容易多了。
我们假设函数bool contains(int x,int y)来判断x的素数集包含y的素数集,那么判断其素数集相等的函数为:

bool judge(int x,int y)
{
    return contains(x,y) && contains(y,x);
}

接下来,完成函数contains()即可。很显然的,我们设g=gcd(x,y)。我们让y充分的去除以g,以至于y尽可能地小。然后递归判断此时的y是否依旧是x素数集的子集。
那么什么情况递归结束呢?显然,当y=1的时候,返回肯定是true。如果y不为1,且x与y互质,则返回肯定是false。
所以contains()函数很容易就写出来了。

bool contains(int x,int y)
{
    int g;
    if(y==1) return true;
    g=gcd(x,y);
    if(g==1) return false;
    while(y%g==0)
        y/=g;
    return contains(x,y);
}

最后,我贴出完整的代码:

#include<stdio.h>
#include<math.h>
#include<string.h>
#define MIN(x,y) ((x)<(y)?(x):(y))
#define MAX(x,y) ((x)>(y)?(x):(y))
#define ABS(x) (((x)>0)?(x):(-(x)))
#define bool int
#define true 1
#define false 0
#define TRUE 1
#define FALSE 0
#define int64 long long

#define MAXLEN 1000005

int gcd(int x,int y)
{
    int c;
    while(x%y!=0)
    {
        c=x%y;
        x=y;
        y=c;
    }
    return y;
}

bool contains(int x,int y)
{
    int g;
    if(y==1) return true;
    g=gcd(x,y);
    if(g==1) return false;
    while(y%g==0)
        y/=g;
    return contains(x,y);
}

bool judge(int x,int y)
{
    return contains(x,y) && contains(y,x);
}

void main()
{
    int n,a,b,c;
    scanf("%d",&n);
    while(n--)
    {
        scanf("%d%d%d",&a,&b,&c);
        if(judge(a,b) && judge(b,c))
            printf("YES\n");
        else printf("NO\n");
    }
}

结果:Accept

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值