欧几里德算法和唯一分解定理

刘汝佳《入门经典》上提供了一道经典的题目:

除法表达式,在NYOJ上可以找到原题,题号1013

描述
        给出一个这样的除法表达式:X1/X2/X3/···/Xk,其中Xi是正整数。除法表达式应当按照从左到右的顺序求和,例如表达式1/2/1/2值为1/4。但是可以在表达式中嵌入括号以改变计算顺序,例如表达式(1/2)/(1/2)的值为1.
输入
        首先输入一个N,表示有N组测试数据, 每组数据输入占一行,为一个除法 表 达式,输入保证合法。 使表达式的值为整数。k<=10000,Xi<=100000000.
输出
        输出YES或NO
样例输入
        1
            1/2/1/2
样例输出
         YES
首先经过推算可知x1恒为分子,x2恒为分母,而其余的数字都可以通过括号移到分子上去
那么就可以写成x1*x3*x4........*xk/x2
只要上面乘积能够整除x2就可以化整。
首先,可以使用欧几里德算法,对于每一个xi,x2除以xi与x2的最大公约数gcd

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
char ch[50010];  //注意数字最长9位,而且还会有/字符
int gcd(int x,int y)
{
    if(x<y) swap(x,y);  //这个判断可以节省一点时间
    return y==0?x:gcd(y,x%y);
}
int main()
{
    int T;
    for(scanf("%d",&T);T;T--)
    {
        scanf("%s",ch);
        int top=0,flag=0;
        int tmp1,tmp2,tmp;
        tmp=0;tmp2=0,tmp1=0;;
        for(int i=0,len=strlen(ch);i<len;i++)
        {
            if(ch[i]>=‘0‘&&ch[i]<=‘9‘)
            {
                tmp=tmp*10+ch[i]-‘0‘;
                if(i==len-1)
                {
                    if(top==1)
                    {
                        tmp2=tmp;
                        tmp2/=gcd(tmp2,tmp1);
                    }
                    if(top==0) tmp1=tmp;
                    if(top>1) tmp2/=gcd(tmp2,tmp);
                }
            }
            else
            {
                if(top==0) tmp1=tmp;
                if(top==1)
                {
                    tmp2=tmp;
                    tmp2/=gcd(tmp2,tmp1);
                }
                if(top>1) tmp2/=gcd(tmp2,tmp);
                top++;
                tmp=0;
            }
            if(tmp2==1) {flag=1;break;}
        }
        if(flag) puts("YES");
        else     puts("NO");
    }
    return 0;
}
        

然而这道题还可以利用唯一分解定理求解,而可惜的是10的8次方会有5761455个素数,考虑最坏情况,时间上难以承受
唯一分解定理:每一个自然数都可以分解成一个或者多个素数相乘的形式(n=p1^a1*p2^a2*.....*pm^am)

只要分别求得x2和所有分子的pi指数,如果对于某个pi指数x2大于所有分子的话,那就无法化整了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#define SET(a) memset(a,0,sizeof(a))
using namespace std;
const int Max=50010;
char ch[Max];
int cnt1[100000000],cnt2[100000000];
void take(int x)
{
    int flag=0;if(x==2) flag=1;
    for(int i=2;i<=x;i++)
    {
        if(x%i==0)
        {
            while(x%i==0)
            {
                x/=i;
                cnt1[i]++;
            }
        }
        if(x==1) break;
    }
}
int main()
{
    int T;
    for(scanf("%d",&T);T;T--)
    {
        scanf("%s",ch);
        int tmp=0,top=0,tmp2=0;
        SET(cnt1);SET(cnt2);
        for(int i=0,len=strlen(ch);i<len;i++)
        {
            if(ch[i]>=‘0‘&&ch[i]<=‘9‘)
            {
                tmp=tmp*10+ch[i]-‘0‘;
                if(i==len-1)
                {
                    take(tmp);
                }
            }
            else
            {
                if(top==1) tmp2=tmp;
                if(top!=1) take(tmp);
                tmp=0;
                top++;
            }
        }
        int flag=0;
        for(int i=2;i<=tmp2;i++)
        {
            if(tmp2%i==0)
            {
                while(tmp2%i==0)
                {
                    cnt2[i]++;
                    tmp2/=i;
                }
            }
            if(cnt2[i]>cnt1[i]) {flag=1;break;}
            if(tmp2==1) break;
        }
        if(flag) puts("NO");
        else     puts("YES");
    }
    return 0;
}

时间: 2024-12-29 07:21:55

欧几里德算法和唯一分解定理的相关文章

数论初步——欧几里得算法和唯一分解定理

具体内容参见紫书p310-p312 一.辗转相除法 恒等式:gcd(a,b) = gcd(b,a%b) 边界条件:gcd(a,0) = a 辗转相除法的关键(恒等式)和边界条件一起构成了下面的程序: int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); } 这个算法称为欧几里得算法!!!! 二.求lcm 公式:gcd(a,b) * lcm(a,b) = a * b 正确的写法(先除后乘):lcm(a,b) = a / gcd(a,b)

HDU 1452 Happy 2004(唯一分解定理)

题目链接:传送门 题意: 求2004^x的所有约数的和. 分析: 由唯一分解定理可知 x=p1^a1*p2^a2*...*pn^an 那么其约数和 sum = (p1^0+p1^1^-+p1^a1)*-* (pn^0+pn^1^-+pn ) 代码如下: #include <iostream> #include <cstring> #include <algorithm> #include <cstdio> using namespace std; const

NOIP2009Hankson 的趣味题[唯一分解定理|暴力]

题目描述 Hanks 博士是 BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫 Hankson.现 在,刚刚放学回家的 Hankson 正在思考一个有趣的问题. 今天在课堂上,老师讲解了如何求两个正整数 c1 和 c2 的最大公约数和最小公倍数.现 在 Hankson 认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公 倍数”之类问题的“逆问题”,这个问题是这样的:已知正整数 a0,a1,b0,b1,设某未知正整 数 x 满足: 1. x 和 a0 的最大公约

Coderforce-574C Bear and Poker(素数唯一分解定理)

题目大意:给出n个数,问能不能通过让所有的数都乘以2的任意幂或乘以3的任意幂,使这n个数全都相等. 题目分析:最终n个数都是相等的,假设那个数为x,根据素数唯一分解定理,x能分解成m*2p3q.所以,只需将所有的a[i]一直除以2并且一直除以3,最终只需判断这n个数是否全部相等即可. 代码如下: # include<iostream> # include<cstdio> # include<cmath> # include<string> # include

唯一分解定理(算术基本定理)及应用

算术基本定理:任何一个大于1的自然数 N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积 N = p1^a1 * p2^a2 * p3^a3 * ... * pn^an (其中p1.p2.... pn为N的因子,a1.a2.... .an分别为因子的指数) 这样的分解称为 N 的标准分解式 应用: (1)一个大于1的正整数N,如果它的标准分解式为: N = p1^a1 * p2^a2 * p3^a3 * ... * pn^an (2)N的因子个数     M(N)= (1 + a1)*(1

uva 10375 唯一分解定理 筛法求素数【数论】

唯一分解理论的基本内容: 任意一个大于1的正整数都能表示成若干个质数的乘积,且表示的方法是唯一的.换句话说,一个数能被唯一地分解成质因数的乘积.因此这个定理又叫做唯一分解定理. 举个栗子:50=(2^1)*(5^2) 题目一般的思路就是要把素数表打出来,eg上面的例子 e={1,0,2,0,0......} 下面是两个题目,仅说说大致的思想: 题目一: E=(X1*X3*X4* ...*Xk)/X2   判断E是不是整数 如果把(X1*X3*X4* ...*Xk)分解成素数相乘,将X2也分解成素

POJ1845Sumdiv(求所有因子和 + 唯一分解定理)

Sumdiv Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 17387   Accepted: 4374 Description Consider two natural numbers A and B. Let S be the sum of all natural divisors of A^B. Determine S modulo 9901 (the rest of the division of S by 99

LightOJ 1341 - Aladdin and the Flying Carpet (唯一分解定理 + 素数筛选)

http://lightoj.com/volume_showproblem.php?problem=1341 Aladdin and the Flying Carpet Time Limit:3000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Submit Status Practice LightOJ 1341 Description It's said that Aladdin had to solve seven

HDU 6069 Counting Divisors(唯一分解定理+因子数)

http://acm.hdu.edu.cn/showproblem.php?pid=6069 题意: 思路: 根据唯一分解定理,$n={a_{1}}^{p1}*{a2_{}}^{p2}...*{a_{m}}^{pm}$,那么n的因子数就是 n的k次方也是一样的,也就是p前面乘个k就可以了. 先打个1e6范围的素数表,然后枚举每个素数,在[ l , r ]寻找该素数的倍数,将其分解质因数. 到最后如果一个数没有变成1,那就说明这个数是大于1e6的质数.(它就只有0和1两种选择) 1 #includ