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

  • 相关阅读:
    1024X768大图 (Wallpaper)
    (Mike Lynch)Application of linear weight neural networks to recognition of hand print characters
    瞬间模糊搜索1000万基本句型的语言算法
    单核与双核的竞争 INTEL P4 670对抗820
    FlashFTP工具的自动缓存服务器目录的功能
    LDAP over SSL (LDAPS) Certificate
    Restart the domain controller in Directory Services Restore Mode Remotely
    How do I install Active Directory on my Windows Server 2003 server?
    指针与指针变量(转)
    How to enable LDAP over SSL with a thirdparty certification authority
  • 原文地址:https://www.cnblogs.com/2017SSY/p/8535270.html
Copyright © 2011-2022 走看看