今天,就来说说杭电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).
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
76HintIn 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
解题思路:
三种方法
1.直接计算(如果你有足够的时间的话!)
代码如下:
scanf("%d",&n);
pr=1;
for(i=1;i<=n;i++){
pr=(pr*(n%10))%10;
}
printf("%d\n",pr);
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;
}
}
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;
}
}
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;
}
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
- 今天,就来说说杭电n^m!
- 输出n-m-n
- 今天来说说html5的拖拽
- 今天我们来说说项目管理
- 今天来说说正则匹配姓名的
- 就来说说Asp.net 身份验证、授权
- 在M个已知数中就N个最大数(ZZ)
- 从N个人中每数m个人就退出该人的一类笔试题
- poj 1036 n!/(n-m)!*m!
- 就为了今天
- 就在今天开始
- 就从今天开始
- 就从今天开始
- m选n算法
- M选N
- M*N的矩阵
- sigma(n^m)
- m的n次方
- 数字图像处理,经典对比度增强算法
- 网络编程之非阻塞socket的连接
- 在oracle数据库里创建自增ID
- 直接用socket实现HTTP协议(下载专用)
- form表单input标签
- 今天,就来说说杭电n^m!
- Cocos2d-x 3.0---触摸机制
- 字符串匹配之kmp
- iOS多线程编程之NSThread的使用
- NanguoCoffee 知道为啥HashMap里面的数组size必须是2的次幂?
- Java中RandomAccessFile的用法
- 基于Canvas的Char.js库使用
- HTML5的图像系统Canvas与SVG
- 九度题目1011:最大连续子序列