找规律!
求N!最后非0位的值。比如2是120的最后一个不是0的值。
输入N比较大,要大数保存。
注意到最后0的个数是与5的因数的个数相等。设f(n)为n!的最后非0位。
那么f(n)=((n%5)!* f(n/5) *2^(n/5))%10
因数2的个数始终大于5,从1开始每连续5个划分为1组,其中5的倍数只提取出一个因数5后,
组成一个新的数列1到n/5,我们有1*2*3*4*5=6*7*8*9*5=2(取最后一个非0位),这里就是2^(n/5)。
再乘上剩下来的几个数字即可
(比如n是123,那么第一次会剩下121,122,123三个数没有被分配)。
例如:23 就可以变为 f(23) = ((3)! * f(4) * 2^(4))%10; f(4) = 4;
故f(23) = 4; 参考http://blog.csdn.net/yihuikang/article/details/7721875
1 2 26 125 3125 9999
1 2 4 8 2 8
#include<stdio.h> #include<string.h> const int di[4] = { 6, 2, 4, 8};//这是2的次幂最后一位的循环; const int pre[10] = { 1, 1, 2, 6, 4,2,2,4,2,8};//前十个数的最后一位; int a[200], ls; char s[200]; void tran( int ls )//转换 将个位放在a[0]处 { for( int i =ls-1; i >= 0; i -- ) a[ls-i-1] = s[i]-'0'; } void mult( ) { int i, t=0;//t是借位; for( i = ls-1; i >= 0; i -- ) { int q = t*10+a[i]; a[i] = q/5; t = q%5; } while( ls > 0&&a[ls-1] == 0 ) --ls;//排除后面的0 仔细考虑一下 } int la_no_num( ) { if( ls == 1 ) return pre[a[0]]; //如果只有一位直接输出或返回 int x1 = pre[a[0]%5]; //这是f(n%5) mult( ); int x2 = di[(a[0]+a[1]*10)%4];//这是2^(n/5) 为什么只算前两位(提示:同余定理) int ans = (x1*x2*la_no_num())%10;//f(n)=((n%5)!* f(n/5) *2^(n/5))%10 return ans; } int main() { int la, i; while( ~scanf( "%s", s ) ) { ls = strlen(s); tran(ls); printf( "%d\n", la_no_num() ); } }
hdoj Last non-zero Digit in N! 【数论】,布布扣,bubuko.com
hdoj Last non-zero Digit in N! 【数论】
原文:http://blog.csdn.net/shengweisong/article/details/31021157