NYOJ_1013除法表达式

大体描述:

给出一个除法表达式:X1/X2/X3/…/Xk,其中Xi为正整数。除法表达式应当按照从左到右的顺序求和,例如,表达式1/2/1/2的值为1/4。但是可以在表达式中嵌入括号改变计算顺序,例如,表达式(1/2)/(1/2)的值为1.

输入X1,X2…,Xk,判断是否可以通过添加括号,使表达式的值为整数。K<=10000,Xi<=10^9;


可以分析出来我们只需要判断X1*X3…Xk/X2是否为整数即可。

一:高精度运算,

   由题目所给的范围可以知道,必须利用高精度才能存储X1…Xk的乘积,所以只需要用高精度运算进行K-2次乘法和1次除法即可。

   此方法有点麻烦,只做分析

二:唯一分解定理

   分析:由唯一分解定理,X2=P1^A1*P2^A2…P2*An,(其中Pi为质数)

   所以利用唯一分解定理,我们就只需要依次判断Pi的指数Ai是否不大于X1*X3…Xk里面Pi的指数ai即可。

   给出AC代码如下:

 

 
#include <iostream>
#include <cstring>
#include <stdio.h>
using namespace std;
int item[10005];
int nums[100][2];//long long 类型的数据分解为质数相乘不超过16位
int ptot[100];

void solve(int num1)
{
    memset(ptot,0,sizeof(ptot));
    int num2=nums[0][0];
    int i,j;
    for(i=1;i<=num2;i++)
    {
        int p=nums[i][0];
        for(j=1;j<=num1;j++)
        {
            int q=item[j];
            if(j==2) continue;
            while(q%p==0){q/=p;ptot[i]++;}
        }
        if(ptot[i]<nums[i][1]){cout<<"NO"<<endl; return;}
    }
    cout<<"YES"<<endl;

}
void depart(int m)//分解m
    {
        int&num = nums[0][0]=0;//nums[0][0]是表头,存放总的个数,用引用比较方便
        num = 0;
        for (int i = 2; i*i <= m;i++)
        if (m%i == 0)
        {
            nums[++num][0] = i;
            nums[num][1] = 0;
            do
            {
                nums[num][1]++;
                m /= i;
            } while (m%i == 0);//将i除干净
        }
        if (m > 1)//如果分解到最后m仍然大于1,说明它是一个素数。注意:如果只是判断素因子有哪些,可以没有此处判断,否则必须有此步
        {
            nums[++num][0] = m;
            nums[num][1] = 1;
        }

    }
int main()
{
    int n;cin>>n;
    while(n--){
       char c;int i;
       for(i=1;;i++)//输入除法表达式
       {
           scanf("%d",&item[i]);
           c=getchar();
           if(c=='\n') break;
       }
       if(i==1) cout<<"YES"<<endl;
       else{
        depart(item[2]);
        solve(i);
       }
    }
    return 0;
}        


三:欧几里得算法

分析:我们可以直接约分,依次将X1,X3,…Xk与X2约去它们的最大公约数,如果最后X2为1,则说明可以,反之不行

给出AC代码:

  

   
#include <iostream>
#include <stdio.h>
using namespace std;
const int K=10005;
int num[K];

int gcd(int a, int b){
    return b==0?a:gcd(b,a%b);
}
bool solve(int s)
{
    num[2]/=gcd(num[1],num[2]);
    if(num[2]==1) return true;
    for(int i=3;i<=s;i++){
        num[2]/=gcd(num[2],num[i]);
        if(num[2]==1) return true;
    }
    return false;
}

int main()
{
    int n;cin>>n;
    while(n--){
       char c;int i;
       for(i=1;;i++)//除法表达式的输入
       {
           scanf("%d",&num[i]);
           c=getchar();
           if(c=='\n') break;
       }
       if(i==1) cout<<"YES"<<endl;
       else {
            if(solve(i)) cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
       }
    }
    return 0;
}
        

注:以上方法参考刘汝佳老师的《算法竞赛入门经典》,


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值