N的N次方的个位数、暴力打表、快速幂取模
N的N次方 取个位数是什么
暴力打表就是用比较小的范围看看有什么规律 比如这道题 算出50以内
1 for(int i=1;i<50;i++) 2 { 3 int sum =1; 4 for(int j=1;j<=i;j++) { 5 sum*=i; 6 if(sum>10) 7 sum%=10; 8 } 9 System.out.print(sum); 10 }
结果:1476563690163656749014765636901636567490147656369
可发现每20就循环
所以可以直接弄一个数组存起来就好了
1 while(n-->0) 2 { 3 int a[]= {1,4,7,6,5,6,3,6,9,0,1,6,3,6,5,6,7,4,9,0}; 4 int b=cin.nextInt(); 5 int c = (b-1)%20; //要b-1 数组下标从0开始 6 System.out.println(a[c]); 7 }
这道题也可以找出规律:
1 /* 2 1的所有次方都是1 3 0的所有次方都是0 4 5的所有次方都是5 5 6的所有次方都是6 6 2^1=2 2^2=4 2^3=8 2^4=6(四个一循环) 7 3^1=3 3^2=9 3^3=7 3^4=1(四个一循环) 8 7^1=7 7^2=9 7^3=3 7^4=1(四个一循环) 9 4^1=4 4^2=6(两个一循环) 10 8^1=8 8^2=4(两个一循环) 11 9^1=9 9^2=1(两个一循环) 12 刚好除尽一个循环余数为0 下标对应为0 所以放在下边为0的位置 13 */ 14 int a[][] = {{0},{1},{6,2,4,8},{1,3,9,7},{6,4},{5},{6},{1,7,9,3,},{6,8,4,2},{1,9}}; 15 16 while(n-->0) { 17 int b= cin.nextInt(); 18 int c=b%10; 19 if(c==0||c==1||c==5||c==6) { 20 System.out.println(c); 21 }else if(c==4||c==9) 22 System.out.println(a[c][b&2]); 23 else 24 System.out.println(a[c][b%4]); 25 }
取模运算:
(a + b) % p = (a % p + b % p) % p …………………………(1)
(a - b) % p = (a % p - b % p) % p …………………………(2)
(a * b) % p = (a % p * b % p) % p …………………………(3)
a ^ b % p = ((a % p)^b) % p …………………………………(4)
根据(3)可知道积的取模等于取模的积再取模、某个因子取模之后相乘再取模保持余数不变。
所以这道题可以这么算
1 int s=1; 2 n=n%10; 3 for(i=0;i<n;i++){ 4 s=(s*n)%m;//本来是s=s*n 但是还有可能内存溢出 根据某个因子取模之后相乘再取模保持余数不变 所以在这里可以多取一次模 5 } 6 s=s%m;
但是这里的时间复杂度还是O(n)
快速取模的原理:
根据这个思路虽然变成了O(n/2),但是可以发现k的b/2次方又可以变成L的b/4次方(L=k的平方)一直迭代下去,所以就有了快速幂取模的方法了如下所示:
1 //方法:快速幂取模 2 while(n-->0) { 3 int a=cin.nextInt(); 4 System.out.println(PowerMod(a, a, 10)); 5 } 6 7 } 8 public static long PowerMod(int a, int b, int c){ 9 long ans = 1; 10 a = a % c; 11 while(b>0) { 12 if(b % 2 == 1) 13 ans = (ans * a) % c; 14 b = b/2; 这是除于2 如果是偶数倒数第二次b为1 然后ans还是会变化 15 a = (a * a) % c; 16 17 return ans; 18 19 }
这里时间复杂度是O(logN)