zoukankan      html  css  js  c++  java
  • NYOJ-1013除法表达式

    除法表达式

    时间限制:1000 ms  |  内存限制:65535 KB
    难度:3
     
    描述

        给出一个这样的除法表达式: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

    (1)思路方向分析

    不难知道整个表达式最后一定会变成这样的形式:A/B

    而A,B都可以表达为这些数中某一部分的乘积。自然就会想到B越小越好,最好是1,这样就可以变成整数了~( ̄▽ ̄)"

    经过一些尝试后会发现,X2必然在B中,而其他数都可以在上,这样问题就简单明了了

    设 E=(X1X3X4X5X6...Xk)/X2  只需要判断E是否为整数即可!(ง •_•)ง

    (2)方法

    方一:

    简单粗暴直接算,不会高精度的会溢出,会高精度的打码打到手抽(;´д`)ゞ

    方二:

    使用唯一分解定理,把X2拆了,然后看看剩下所有的Xi们能不能贡献出所需的pi对应的次数ai,这个方法很正确,但还可以更优化一点

    方三:

    没错就是直接约分~!每次把X2除掉与Xi的gcd,这样除k遍后如果X2是1那么E就是整数啦~(●ˇ∀ˇ●)

    口以这么写:

    bool judge(int *X) {
    	X[2] /= gcd(X[2],X[1]);
    	for(int i = 3;i <= k;i++) X[2] /= gcd(X[i],X[2]);
    	return X[2] == 1;
    }
    

      这个算法的关键是gcd,而这也是我学习这道题的主要目的。

    推荐这个文章,写的真是太好了(´▽`ʃ♡ƪ),另外下方的评论也请不要错过!!

    这个文章给出的最强gcd如下,O(log(max(a, b)))

    int superGcd(int a,int b)
    {
    	if(a==0)return b;
    	if(b==0)return a;
    	if(!(a&1)&&!(b&1))return superGcd(a>>1,b>>1)<<1;
    	else if(!(b&1))return superGcd(a,b>>1);
    	else if(!(a&1))return superGcd(a>>1,b);
    	else return superGcd(abs(a-b),min(a,b));
    }
    

      相关证明可以进一步的查看这里

    假设有两个数x和y,存在一个最大公约数z=(x,y),即x和y都有公因数z,
    那么x一定能被z整除,y也一定能被z整除,所以x和y的线性组合mx±ny也一定能被z整除。(m和n可取任意整数)

    对于辗转相除法来说,思路就是:若x>y,设x/y=n余c,则x能表示成x=ny+c的形式,将ny移到左边就是x-ny=c,由于一般形式的mx±ny能被z整除,

    所以等号左边的x-ny(作为mx±ny的一个特例)就能被z整除,即x除y的余数c也能被z整除。

    而更相减损术则就是把x/y=n余c变成x-y=c同样都可以被z整除,所以把c与x或y放在一起求gcd都是不变的

    我再说一遍,位移大法好啊啊啊啊啊

    #include <cstdio>
    using namespace std;
    int n,X[10005],k;
    char w;
    int min(int a,int b)
    {
    	if(a<b)return a;
    	else return b;
    }
    int abs(int a)
    {
    	if(a<0)return 0-a;
    	else return a;
    }
    int gcd(int a,int b)
    {
    	if(a==0)return b;
    	if(b==0)return a;
    	if(!(a&1)&&!(b&1))return gcd(a>>1,b>>1)<<1;
    	else if(!(b&1))return gcd(a,b>>1);
    	else if(!(a&1))return gcd(a>>1,b);
    	else return gcd(abs(a-b),min(a,b));
    }
    bool judge(int *X) {
    	X[2] /= gcd(X[2],X[1]);
    	for(int i = 3;i <= k;i++) X[2] /= gcd(X[i],X[2]);
    	return X[2] == 1;
    }
    int main()
    {
    	scanf("%d",&n);
    	while(n--)
    	{
    		k=1;
    		scanf("%d",&X[1]);
    		w=getchar();
    		do{
    			scanf("%d",&X[++k]);
    			w=getchar();
    		}while(w=='/');
    		if(judge(X))printf("YES
    ");
    		else printf("NO
    ");
    	}
    	return 0;
    }
    

      所以以上为完整呆码~( ̄▽ ̄)"

    顺带一提,如果你用欧几里得算法来求gcd,那么递归层数不会超过 4.785lgN+1.6723


    我想我接下来就应该弄拓展欧几里得吧。。。

    end——2018/3/9

  • 相关阅读:
    hdu 5253 最小生成树
    hdu5248 序列变换
    bjfu1299 stl使用
    bjfu1277 简单递归
    bjfu1262 优先队列
    bjfu1287字符串输出的大水题
    bjfu1281
    bjfu1253 最大上升子序列和
    [转][Unity3D]引擎崩溃、异常、警告、BUG与提示总结及解决方法
    Unity3d 中 将远程 MySQL 数据库转换为本地 Sqlite
  • 原文地址:https://www.cnblogs.com/2017SSY/p/8535270.html
Copyright © 2011-2022 走看看