Num 16: HDOJ: 题目1061 : Rightmost Digit [ 求个位数 ] [ 快速幂算法 ]

来源:互联网 发布:客户地图软件 编辑:程序博客网 时间:2024/06/11 20:41



题目:

Rightmost Digit

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 39386    Accepted Submission(s): 14861


Problem Description
Given a positive integer N, you should output the most right digit of N^N.
 

Input
The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.
Each test case contains a single positive integer N(1<=N<=1,000,000,000).
 

Output
For each test case, you should output the rightmost digit of N^N.
 

Sample Input
234
 

Sample Output
76
Hint
In the first case, 3 * 3 * 3 = 27, so the rightmost digit is 7.In the second case, 4 * 4 * 4 * 4 = 256, so the rightmost digit is 6.


     刚看到题的时候就应该意识到,一定不能强行计算 N^N%10 然后输出,计算量大,而且会数据溢出;

     大数乘法在这里也不太合适,毕竟要算N次方,就算计算出来,submit 的时候也不能够保证不超时;

     所以感觉到应该是有内在规律,仔细研究后发现:


1.

   在计算 N^N 的个位数的时候,个位数的数值仅与N的个位数有关;

    所以可以利用计算( N%10 )^N 的个位数来代替原题;


2.

     进一步的,演算后发现1-9的N( N>0 )次方按4个数一循环;

    例:3的1-9次方的个位数依次为 ( 3, 9,7,1,3,9,7,1,3) ;

    所以对于次方数也可以做简化,次方为:N%4 ;

    这里要注意,当N%4==0的时候N应当取4;( 否则X^0=1,只会输出1 )


     通过以上的分析,我们就将问题转化为求 ( N%10 )^( N%4 )的个位数的问题了;

    大大简化了计算过程,而且保证了数据一定不会溢出;


AC代码:

<span style="font-size:18px;">#include<stdio.h>#include<math.h>int main(){int t;scanf("%d",&t);while(t--){int n,num,index;scanf("%d",&n);num=n%10;index=n%4;if(index==0) index=4;printf("%d\n",(int)(pow((double)num,index))%10);}return 0;}</span>

     注意:pow函数的格式pow( double x, int index ),要学会利用类型的强制转换;


     见网上也有许多人在说用快速幂的方法也可以做;

    这里仅介绍快速幂算法,不推荐在这道题上使用快速幂的方法;



快速幂:

   

    分为二分法和位运算( 位操作 );

    原理:

    例如在计算 2^4 的时候,当计算过 2^2后, 可以直接计算 ( 2^2 )^2即可;

   

      1.二分法:


<span style="font-size:18px;">#include<stdio.h>int pow2(int a,int b)// a:底数 b:指数{    int r=1,base=a;while(b!=0){           if(b%2) r*=base; // 如果次方为奇数,r乘一个底数( 使次方变为偶数 );            base*=base;      // 每计算循环一次,底数所乘的数都为上一次的平方倍,减少次数;   b/=2;}        return r;}int main(){    int a,b;    while (scanf("%d%d",&a,&b))    printf("%d\n",pow2(a,b));}</span>


      2.位运算:


  原理和二分法相似,只不过是通过位运算来对数据做处理的;


<span style="font-size:18px;">#include<stdio.h>int pow3(int a,int b){int r=1,base=a;while(b!=0){if(b&1)r*=base;base*=base;b>>=1;}return r;}int main(){    int a,b;    while (scanf("%d%d",&a,&b))    printf("%d\n",pow3(a,b));}</span>

   

     我们也可以用计算快速幂的方法来进行余数的计算( 求个位数即对10取余 ):

   这里用到的方法为:


   快速幂取模算法:


    利用离散数学之中所讲的知识,我们有公式:

    ( a^b ) mod c=( a mod c )^b mod c ;

    通过数学知识,我们可化简此等式有( 可循环[ 递归 ]计算 ):

    奇数时:(a mod c) * ( a^2 mod  c)^( b/2 ) mod c ;

    偶数时: a^2 mod  c)^( b/2 ) mod c ;

  所以在计算 N^N 的个位数的时候,解决了 N^N可能太大存不下的问题,也减少了步数

<span style="font-size:18px;">#include<stdio.h>int powermod(int a, int b, int c){  int rest=1;  a=a%c;//公式中的( a mod c )  while(b>0)//类似于二分法分步求余  {    if(b%2==1) rest=(rest*a)%c;    b=b/2;    a=(a*a)%c;  }  return rest;}int main(){int base,index,rest;while(scanf("%d%d%d",&base,&index,&rest)) printf("%d\n",powermod(base,index,rest));}</span>

   函数用 a^b%c 的快速计算 ;






1 0
原创粉丝点击