算法 64式 19、数学算法整理

1 算法思想

 

2 数学系列

类别-编号

题目

遁去的一

1

特殊乘法

写个算法,对2个小于1000000000的输入,求结果。

特殊乘法举例: 123 * 45 = 1*4 + 1*5 + 2*4 + 2*5 + 3*4 + 3*5

计算机考研—机试指南

https://blog.csdn.net/qingyuanluofeng/article/details/47160787

关键:利用字符串去'0'的投机取巧方法

 

 

//方法2:利用当成字符串进行处理

int main(int argc,char* argv[])

{

       char sData1[20],sData2[20];

       int iSum = 0;

       while(EOF!=scanf("%s %s",sData1,sData2))

       {

              for(int i = 0; sData1[i]!='\0' ; i++)

              {

                     for(int j = 0 ; sData2[j]!='\0' ; j++)

                     {

                            iSum += (sData1[i]-'0')*(sData2[j]-'0');

                     }

              }

              printf("%d",iSum);

       }

       getchar();

       return 0;

}

2

又一版A+B

输入两个不超过整型定义的非负10进制整数A和B(<=231-1),输出A+B的m(1<m<10)进制数

计算机考研—机试指南

https://blog.csdn.net/qingyuanluofeng/article/details/47160827

关键:

1打印的时候逆序打印,得到从低位到高位。m进制转换问题。

2因为每个数的范围是10 0000 0000,所以只能用long long不会溢出

3使用scanf和printf输出long long Yong %lld

4必须对0做特殊处理,因此这里用do while循环

 

 

int main(int argc,char* argv[])

{

       //int m,iNum1,iNum2;//易错,iNum1和iNum2必须用long long

       int m;

       long iNum1,iNum2;

       //int iBit[100];

       //int iResult[20];

       while(EOF!=scanf("%d",&m) && m!=0 )

       {

              scanf("%ld %ld",&iNum1,&iNum2);

              int j = 0;

              int iBit[100];

              long iSum = iNum1 + iNum2;

              /*易错,必须用do..while循环,防止遗漏对0的处理

              while(iSum)

              {

                     iBit[j++] = iSum % m;

                     iSum /= m;

              }

              */

              do{

                     iBit[j++] = iSum % m;

                     iSum /= m;

              }while(iSum);

              //将每一位转换为该整数

              j--;

              for(;j >= 0 ; j--)

              {

                     printf("%d",iBit[j]);

              }

              printf("\n");

       }

       system("pause");

       getchar();

       return 0;

}

3

数制转换

求任意两个不同进制非负整数的转换,所给整数在long范围。不同进制的表示符号为(0,1,...,9,a,b,...,f)或者(0,1...,9,A,B,...,F)

输入:

一行,3个整数a,n,b.a表示其后的n是a进制整数,b表示欲将a进制整数n转换成b进制整数。a,b是十进制整数,2<=a,b<=16

输出:

该整数转换后的b进制数,字母符号大写表示(0,1,...,9,A,B,...,F)

 

输入:

15 Aab3 7

输出:

210306

计算机考研—机试指南

https://blog.csdn.net/qingyuanluofeng/article/details/47160875

提示:可以用字符串表示不同进制的整数

思路:

a->10->b

a进制先转换为10进制,利用各位依次乘以10的0次方,1次方,。。。.10进制转换为进制,利用除k取余法。

 

代码:

int main(int argc,char* argv[])

{

       long a,b;

       char n[20];

       while(EOF!=scanf("%d %s %d",&a,n,&b))

       {

              long lSum = 0;

              for(int i = 0 ; n[i]!='\0' ; i++ )

              {

                     //关键还需要将a转换为10

                     int x;

                     if(n[i] <= 'z' && n[i] >= 'a')

                     {

                            x = n[i] - 'a' + 10;

                     }

                     else if(n[i] <= 'Z' && n[i] >= 'A')

                     {

                            x = n[i] - 'A' + 10;

                     }

                     else if(n[i] <= '9' && n[i] >= '0')

                     {

                            x= n[i] - '0';

                     }

                     //lSum += lSum*a + x;//易错,这里不是lSum +=,而是lSum =

                     lSum = lSum*a + x;

                     //printf("%ld",lSum);

              }

              printf("%ld\n",lSum);

              //接下来将10进制数转换为b进制数,采用除b取余的方法

              int iBit[20],j = 0;

              char sBit[20];

              do{

                     //iBit[j++] = lSum % b;//易错,这边还需要将超过10的数字转换为字符,所以不管数字和字符统一用字符表示

                     iBit[j] = lSum % b;

                     sBit[j] = iBit[j] < 10 ? (iBit[j] + '0') : (iBit[j] - 10 + 'A');

                     lSum /= b;

                     j++;

              }while(lSum);

              sBit[j] = '\0';

              //逆序打印

              j--;

              for(; j >= 0 ; j--)

              {

                     printf("%c",sBit[j]);

              }

       }

       system("pause");

       getchar();

       return 0;

}

4

最大公约数

求最大公约数。同时满足a%c=0,b%c=0的最大正整数c。若a,b中有一个为0,则最大公约数为非0数。若a,b均为0,则没有最大公约数

 

输入:

49 14

输出:

7

计算机考研—机试指南

https://blog.csdn.net/qingyuanluofeng/article/details/47160885

关键:

1 a=b,b = a%b缩小问题规模

 

代码:

int main(int argc,char* argv[])

{

       int a,b;

       while(EOF!=scanf("%d %d",&a,&b))

       {

              while(true)

              {

                     if(a==0 && b==0)

                     {

                            printf("Have no GCD!");

                            break;

                     }

                     else if(a==0)

                     {

                            printf("%d",b);

                            break;

                     }

                     else if(b==0)

                     {

                            printf("%d",a);

                            break;

                     }

                     else

                     {

 

                            //a = b;

                            //b = a%b;//易错,必须先求a%b,的值,再赋给b,而不能直接用b=a%b

                            int iTemp = a % b ;

                            a = b;

                            b = iTemp;

                     }

              }

       }

       system("pause");

       getchar();

       return 0;

}

5

最小公倍数

给定两个正整数,计算这两个数的最小公倍数

计算机考研—机试指南

https://blog.csdn.net/qingyuanluofeng/article/details/47160905

关键:最小公倍数 = 两数乘积/最大公约数

 

//求最大公约数

int gcd(int a,int b)

{

       if(b==0)//关键:默认b!=0,因为取模的时候b不能为0

       {

              return a;

       }

       else

       {

              return gcd(b,a%b);//其他情况用递归

       }

}

 

int main(int argc,char* argv[])

{

       int a,b;

       while(EOF!=scanf("%d %d",&a,&b))

       {

              int iGCD = gcd(a,b);

              printf("%d",a*b/iGCD);

       }

       system("pause");

       getchar();

       return 0;

}

6

素数判定

给定一个数n,要求判定其是否为素数(0,1,负数都是非素数)

计算机考研—机试指南

https://blog.csdn.net/qingyuanluofeng/article/details/47160935

7

素数

输入一个整数n(2<=n<=100000),要求输出所有从1到这个整数之间(不包括1和这个数)个位为1的素数,如果没有则输出-1。

计算机考研—机试指南

https://blog.csdn.net/qingyuanluofeng/article/details/47160959

素数:只能被自身和1整除的大于1的正整数

假设n存在大于等于sqrt(n)的因数y,则z=n/y必同时为n的因数,且其值<=sqrt(n)

关键:

1要将sqrt(n)的值先计算出来,不能放在循环中,这回导致循环多少次就计算多少次平方根

 

代码:

bool isPrime(int a)

{

       if(a < 1)

       {

              return false;

       }

       else

       {

              int iBound = (int)sqrt(a*1.0);

              //for(int i = 2 ; i <= sqrt(a) ; i++)//技巧:耗时

              for(int i = 2 ; i < iBound ; i++)

              {

                     if(0== a%i )

                     {

                            return false;

                     }

              }

              return true;

       }

}

8

质因数的个数

求正整数N(>1)的质因数的个数。相同的质因数需要重复计算。如120=2*2*2*3*5,共有5个质因数。

 

输入:多组测试数据,每组测试数据的输入时一个正整数N,(1<N<10^9)

输入:120

输出:5

计算机考研—机试指南

https://blog.csdn.net/qingyuanluofeng/article/details/47160989

注意:1不是N的质因数:若N为质数,N是N的质因数

思路:

用素数筛选法预先筛选出可能在题面所给定的数据范围内成为素因数的素数。程序输入待处理数字n时,依次遍历所有小于n的素数,确定为素因数后,通过试除确定对应的幂指数。

求出幂指数的和即为所求。

关键:

1 N最大为10的9次方,因此需要将素因数求到10的9次方的一般即5次方,此时质因数的的幂指数次数为

2 需要建立3个数组,第一个数组用于保存质因数,第二个数组要保存对应质因数的次数

3 它通过不断处理质因数,最终分解该数=1时,应该提前跳出做判断

4 对于如果测试100000内的所有素因数,若n仍未被分解为1,则剩余因数一定是n,大于100000的素因数

5           if(i >= 1000)//这个是用来防止溢出,因为两个大整数相乘可能溢出。这里i>=1000时,基本后面全部筛选过了

              {

                     continue;

              }

 

代码:

int prime[100001];

int primeSize;

bool mark[100001];//因为primeSize会累加到100001,1万没有崩溃,共申请内存40000*4B = 40*4KB = 0.16MB,100000 = 申请1.2MB内存

 

 

//建立起i与质数的关系

void init()

{

       long i ;

       primeSize = 0;

       for( i = 1 ; i <= 100000 ; i++)

       {

              mark[i] = false;//默认为素数,false

       }

       for( i = 2 ; i <= 100000 ; i++ )

       {

              if(true==mark[i])

              {

                     continue;//如果是非素数直接跳过

              }

              prime[primeSize++] = i;//素数

              if(i >= 1000)//这个是用来防止溢出,因为两个大整数相乘可能溢出。这里i>=1000时,基本后面全部筛选过了

              {

                     continue;

              }

              for(long j = i*i ; j <= 10000 ; j += i)//J=I*I超过65535溢出

              {

                     mark[j] = true;//这里发生中断

                     //printf("%d %d",i,j);

              }

       }

}

 

int main(int argc,char* argv[])

{

       init();

       int iNum;

       while(EOF!=scanf("%d",&iNum))

       {

              int ansNum[30];//2的30次方约为1000的3次方为10的9次方

              int iSize = 0;

              int ansSize[30];//保存每个质因数对应的次数

              for(int i = 0 ; i < primeSize ; i++)

              {

                     //如果该数字能够被分解为质因数,统计相应的次数

                     if(iNum % prime[i]==0)

                     {

                            //如果能够分解,就循环分解

                            ansNum[iSize] = prime[i];

                            ansSize[iSize] = 0;//易错,要先给定初始值为0

                            while(iNum % prime[i] == 0)

                            {

                                   ansSize[iSize]++;

                                   iNum /= prime[i];

                            }

                            //不能分解就令

                            iSize++;

                            //易错,如果已经被分解为1,则终止

                            if(1==iNum)

                            {

                                   break;

                            }

                     }

              }

              //如果分解到最后都不成功,则说明该质因数是大于100000,并且只可能次数为1

              if(iNum!=1)

              {

                     ansNum[iSize] = iNum;

                     //ansSize[iSize] = 1;//易错,这里iSize还要进行累加,取下一个

                     ansSize[iSize++] = 1;

              }

              //统计次数

              int iTotalCount = 0;

              for(int k = 0 ; k < iSize ; k++)

              {

                     iTotalCount += ansSize[k];

              }

              printf("%d",iTotalCount);

       }

       getchar();

       return 0;

}

9

整除问题

给定n,a求最大的k,使得n!可以被a的k次方整除,但不能被a的k+1次方整除

 

输入:n(2<=n<=1000),a(2<=a<=1000)

6 10

输出:

1

 

6!=360.可以被10的1次方整除但是不能被10的2次方整除

计算机考研—机试指南

https://blog.csdn.net/qingyuanluofeng/article/details/47161005

思路:累计除以k次为0,第k+1次不为0(错误)

1 a整除b,b/a 若a中存在素因数px ,则b也必存在该素因数,且该素因数在b中对应的幂指数不小于在a中的幂指数.

要求的k,只需要一次测试a中的每一个素因数,确定b中该素因数对应的幂指数是a栈中幂指数的几倍,所有倍数中最小的那个即为我们要求的k

2 对于a和n!分解素因数。n/(p*p)可以向n!提供两个p因子,但它们在之前(p的倍数必包括p*p的倍数)步骤中每个数都已经向计数器累加了1个p因子,此处

它们还能向计数器贡献n/(p*p)个素因子,累加器累加n/(p*p),若n/(p*p)=0,表示没有一个整数能够向n!提供2个或2个以上的p因子

3 一次遍历可能成为其素因子的素数,计算对应的幂指数,可完成对n!的素因数的分解

不懂

 

代码:

 

bool mark[1001];

int prime[1001];

int primeSize;

 

void init()

{

       int i;

       for(i = 1 ; i <= 1000 ; i++)//要注意初始值

       {

              mark[i] = false;//false表示素数

       }

       for(i = 2 ; i <= 1000 ; i++)//必须从2开始,否则就错了

       {

              if(true==mark[i])

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值