今天,就来说说杭电n^m!

来源:互联网 发布:淘宝开店培训机构 编辑:程序博客网 时间:2024/06/05 18:21

杭电1061

先上题目:

Rightmost Digit

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


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.
 


 

Author
Ignatius.L
 


 

Recommend
 


 

Statistic | Submit | Discuss | Note
 
 
解题思路:
三种方法
 
1.直接计算(如果你有足够的时间的话!)
代码如下:
scanf("%d",&n);
  pr=1;
          for(i=1;i<=n;i++){
   pr=(pr*(n%10))%10;
  }
  
   printf("%d\n",pr);
 
 
当然,这在杭电上会超时!因为n足够大的时候,循环次数会较多!不妨可以试试哦!
 
2.就像求素数那样,事先打一个余数表,a[ i ] 存的都是 i^i 的余数,
代码如下:
int a[100000010];
void solve(){
 int i,j;
 memset(a,0,sizeof(a));
 a[1]=1;
 for(i=2;i<1000000010;i++){
  a[i]=(a[i-1]*(i%10))%10;
 }
}
 
这样的确可以,(对于测试数据较小的时候),此时定义的a[100000010]  的程序能够运行,但杭电上的数据正好,又多了一个0;
那好,我们就加上一个0;   运行时,出现了问题,说定义的数组太大,,,,怎么办呢,,,,回忆一下,我们定义的是整型的数组a[1000000010],,,整形四个字节,,并且,根据需要,我们在a数组中只是存放0~10之间的数,那么我们就没有必要用整形,我们完全可以用字符型数组代替,那好,我们就改一下,,,,,,
如下:
char a[1000000010];
void solve(){
 int i,j;
 memset(a,0,sizeof(a));
 a[1]=1;
 for(i=2;i<1000000010;i++){
  a[i]=(a[i-1]*(i%10))%10;
 }
}
 
运行,,!哎呀,这次果然没报错,,那好,我们就提交一下,,,提交得到的是Memory Limit Exceeded,超内存了,,看一下程序内存,70多兆,那必须超啊!所以本题用打余数表的方法不是超时,就是超内存,所以这种打表方法在本题是行不通的,我们还要另寻他法,,接下来,就有了3
 
3.简化运算步骤
 
由上两种方法可知,打余数表,内存太大,,直接运算呢,超时,,,等等,既然运算超时,那一定是运算的时候,运算次数太多了,那么我们是否可以简化一下运算步骤呢,,当然可以,
 
根据 剩余定理可知:
 
                                  (n^m)%10=((n%10)^m)%10
 
然而,先进行求余,是减小了n,,在一定成度上减少了运算次数,关键是把m也减小,这样才能最大程度的较少运算次数,为此,我们可以进行降幂处理
如下:
               m为偶数:  n^m=(n*n)^(m/2)
              
               m为奇数时:n^m=n*(n*n)^(m/2)
 
  根据剩余定理:得  m为偶数:  (n^m)%10=(((n*n)%10)^(m/2))%10
              
                                    m为奇数时:n^m=n*(n*n)^(m/2)  同样是这样
 
由此可得代码如下:
 
 int solve(int n,int m){
 if(m==0) return 1;
 if(m==1) return n;
 if(m%2==0) return solve(n*n%10,m/2);
 if(m%2!=0) return n*solve(n*n%10,(m-1)>>1)%10;
}
 
 
这也是一个较常用的代码片段,完整代码如下:

# include<stdio.h>
int solve(int n,int m){
 if(m==0) return 1;
 if(m==1) return n;
 if(m%2==0) return solve(n*n%10,m/2);
 if(m%2!=0) return n*solve(n*n%10,(m-1)>>1)%10;
}


int main(){
    int n;
    int m,i;
    scanf("%d",&n);
    while(n--){
  scanf("%d",&m);
  printf("%d\n",solve(m%10,m));
 }
 return 0;
}

4,,??这应该也算得上一种方法:

 

将1到40 的n^n运算打印出来,可以惊奇的发现,数是以20为周期,循环的,,那么,我们就又能做点"手脚"了  嘿嘿!!

如下:

#include<iostream>using namespace std;int main(){    int t,a[21]={0,1,4,7,6,5,6,3,6,9,0,1,6,3,6,5,6,7,4,9,0};    __int64 n;    cin>>t;    while(t--)    {        cin>>n;        cout<<a[n%20]<<endl;    }    return 0;}

 

解题时间:2014~07~28

解题人:李富昌

仅供参考!

0 0